PageRenderTime 61ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/src/core/mid.c

https://gitlab.com/magnusr/modem-init-daemon
C | 1156 lines | 932 code | 113 blank | 111 comment | 196 complexity | 7877b349e65c683d90ec71f62d784b2d MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.0, LGPL-2.1
  1. /*
  2. * Copyright (C) 2010 ST-Ericsson AS
  3. * Author: Erwan Bracq / erwan.bracq@stericsson.com
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. *
  17. * See the NOTICE file distributed with this work for additional
  18. * information regarding copyright ownership.
  19. */
  20. #define PERF_MEASUREMENT 1
  21. #include <stdio.h>
  22. #include <unistd.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <errno.h>
  26. #include <getopt.h>
  27. #include <signal.h>
  28. #include <fcntl.h>
  29. #include <sys/types.h>
  30. #include <sys/stat.h>
  31. #include <sys/wait.h>
  32. #include <dlfcn.h>
  33. #include <time.h>
  34. #include <assert.h>
  35. #include <sys/capability.h>
  36. #include <sys/prctl.h>
  37. #include <pwd.h>
  38. #include <grp.h>
  39. #include <apr_general.h>
  40. #include <apr_poll.h>
  41. #include <apr_network_io.h>
  42. #include "mid.h"
  43. #include "mid_caif.h"
  44. #include "mid_conf.h"
  45. #include "mid_dev.h"
  46. #include "mid_error.h"
  47. #include "mid_flash.h"
  48. #include "mid_gpio.h"
  49. #include "mid_ipc.h"
  50. #include "mid_log.h"
  51. #include "mid_mfa.h"
  52. #include "mid_power.h"
  53. #include "mid_settings.h"
  54. #include "mid_statemachine.h"
  55. #include "version.h"
  56. #include "atchannel.h"
  57. #include "crash_dump.h"
  58. #include "mid_sys.h"
  59. #include "mid_fw_upgrade.h"
  60. #if defined(MOTOROLA_FEATURE)
  61. #include "private/android_filesystem_config.h"
  62. struct mot_mid mot_mid_info;
  63. #endif
  64. /* Internal mid structure */
  65. static struct mid mid_info;
  66. #ifdef DEBUG_TRACE
  67. struct mid_dbg mid_dbg_info;
  68. #endif
  69. /* Modem firmware */
  70. static union mid_modem_firmware mod_firm;
  71. /* Primary link device */
  72. static struct mid_dev prim_dev;
  73. /* Secondary link device, used only when link swap is specified */
  74. static struct mid_dev sec_dev;
  75. /* Configuration file processing */
  76. static void (*moli_load_cfgfile)(struct mid *mid_info, const char* cfg_file_name);
  77. /* Default settings for device and modem firmware */
  78. static void (*moli_default_settings)(struct mid *mid_info);
  79. static inline void lock_mid_data(void)
  80. {
  81. apr_status_t status;
  82. if (unlikely((status = apr_thread_mutex_lock(mid_info.mutex)) != APR_SUCCESS)) {
  83. char message[100];
  84. MLGE("MID: Unable to lock internal mid data mutex: %s.",
  85. apr_strerror(status, message, sizeof(message)));
  86. }
  87. }
  88. static inline void unlock_mid_data(void)
  89. {
  90. apr_status_t status;
  91. if (unlikely((status = apr_thread_mutex_unlock(mid_info.mutex)) != APR_SUCCESS)) {
  92. char message[100];
  93. MLGE("MID: Unable to unlock internal mid data mutex: %s.",
  94. apr_strerror(status, message, sizeof(message)));
  95. }
  96. }
  97. #define LOCK_MID_DATA lock_mid_data()
  98. #define UNLOCK_MID_DATA unlock_mid_data()
  99. int stub_moli_get_crash_dump(struct mid *midinfo, struct mid_dev *dev, const char* dump_directory, const char* dump_directory_header, const char* dump_filename, const char* dump_filename_header, int dump_timestamp, crash_dump_report_t report_type, int max_dump_files)
  100. {
  101. UNUSED(midinfo);
  102. UNUSED(dev);
  103. UNUSED(dump_directory);
  104. UNUSED(dump_directory_header);
  105. UNUSED(dump_timestamp);
  106. UNUSED(dump_filename);
  107. UNUSED(dump_filename_header);
  108. UNUSED(report_type);
  109. UNUSED(max_dump_files);
  110. MLGD("STUB: Call stub moli_get_crash_dump function -> this function do nothing.");
  111. return 0;
  112. }
  113. static int stub_moli_configure_security_data(struct mid * mid_info) {
  114. UNUSED(mid_info);
  115. MLGD("STUB: Call stub moli_configure_security_data function -> this function do nothing.");
  116. return 0;
  117. }
  118. static void * stub_moli_boot(struct apr_thread_t* thread, void *arg)
  119. {
  120. UNUSED(arg);
  121. UNUSED(thread);
  122. MLGD("STMACH: MID_LONG_OPS_EVT event set");
  123. SET_FLAG(mid_info.event, MID_LONG_OPS_EVT);
  124. mid_info.long_ops_result = MID_FLBOOT_OK;
  125. MLGD("STUB: Call stub moli_boot function -> this function do nothing.");
  126. return 0;
  127. }
  128. static void stub_moli_default_settings(struct mid *mid_info)
  129. {
  130. UNUSED(mid_info);
  131. MLGD("STUB: Call stub moli_default_settings -> this function do nothing.");
  132. return;
  133. }
  134. static void stub_moli_load_cfgfile(struct mid *mid_info, const char* cfg_file_name)
  135. {
  136. UNUSED(mid_info);
  137. UNUSED(cfg_file_name);
  138. MLGD("STUB: Call stub moli_load_cfgfile -> this function do nothing.");
  139. }
  140. static int stub_moli_fw_upgrade_flash(void)
  141. {
  142. return 0;
  143. }
  144. static void stub_moli_fw_upgrade_init(int *error_code_p)
  145. {
  146. UNUSED(error_code_p);
  147. return;
  148. }
  149. static int stub_moli_fw_upgrade_status(char **status)
  150. {
  151. UNUSED(status);
  152. return 0;
  153. }
  154. static int stub_moli_fw_upgrade_img_xfer(struct mid *mid_info)
  155. {
  156. UNUSED(mid_info);
  157. MLGD("STUB: Call stub moli_fw_upgrade_img_xfer -> this function do nothing.");
  158. return 0;
  159. }
  160. static char * stub_moli_fw_upgrade_get_error_str(struct mid *mid_info, int error_code)
  161. {
  162. UNUSED(mid_info);
  163. UNUSED(error_code);
  164. MLGD("STUB: Call stub moli_fw_upgrade_get_error_str -> this function do nothing.");
  165. return NULL;
  166. }
  167. static void mid_signal_handler(int signal)
  168. {
  169. switch (signal) {
  170. case SIGHUP:
  171. MLGD("SIG: SIGHUP signal catched. Nothing to do.");
  172. break;
  173. case SIGTERM:
  174. MLGD("SIG: SIGTERM signal catched. MID will shutdown the modem in the next step and exit.");
  175. /* Clearing Reboot event and start event */
  176. /* TODO lock - better to replace them by atomic operation if possible */
  177. mid_info.event &= ~(1<<MID_MODEM_START_EVT);
  178. mid_info.event &= ~(1<<MID_IPC_RBT_EVT);
  179. MLGD("STMACH: MID_MODEM_START_EVT event cleared");
  180. MLGD("STMACH: MID_IPC_RBT_EVT event cleared");
  181. mid_info.boot_retry_left = 0;
  182. mid_info.flash_retry_left = 0;
  183. mid_info.shutdown_retry_left = 0;
  184. SET_FLAG(mid_info.event, MID_SIG_KILL_EVT);
  185. MLGD("STMACH: MID_SIG_KILL_EVT event set");
  186. #if defined(MOTOROLA_FEATURE)
  187. if (mot_mid_info.recovery_mode)
  188. mid_mfa_stop(mid_info.mfa, false);
  189. #endif
  190. break;
  191. }
  192. }
  193. static int daemonize(char *rdir, char *pidfile)
  194. {
  195. pid_t pid, sid;
  196. #ifndef HAVE_ANDROID_OS
  197. char pid_str[16];
  198. int fd;
  199. #else
  200. UNUSED(pidfile);
  201. #endif
  202. /* Already a daemon */
  203. if (getppid() == 1) {
  204. MLGD("MID: MID try to daemonize. But the process is already executed in background.");
  205. /* Change the file permissions */
  206. umask(027);
  207. /* Change to running directory */
  208. if (chdir(rdir) < 0) {
  209. MLGW("MID: Failed to change to running dir (specified in mid.conf) \"%s\". MID will run on \"/\" folder.",
  210. rdir);
  211. if (chdir("/") < 0)
  212. MLGE("MID: MID will run from current location, as chdir call failed.");
  213. }
  214. /* Open PID file */
  215. #ifndef HAVE_ANDROID_OS
  216. if (pidfile) {
  217. fd = open(pidfile, O_RDWR|O_CREAT, 0640);
  218. if (fd < 0) {
  219. MLGE("MID: MID cannot open PID file: %s. Process PID will not be recorded.", pidfile);
  220. }
  221. if (lockf(fd, F_TLOCK, 0) < 0) {
  222. close(fd);
  223. MLGE("MID: PID file %s lock failure. Process PID record could be corrupted.", pidfile);
  224. }
  225. /* Record pid to file - Failure are ignored. */
  226. sprintf(pid_str, "%d\n", getpid());
  227. if (fd >= 0) {
  228. write(fd, pid_str, strlen(pid_str));
  229. close(fd);
  230. }
  231. }
  232. #endif
  233. close(STDIN_FILENO);
  234. close(STDOUT_FILENO);
  235. close(STDERR_FILENO);
  236. freopen("/dev/null", "r", stdin);
  237. freopen("/dev/null", "w", stdout);
  238. freopen("/dev/null", "w", stderr);
  239. /* Signal handling
  240. * Ignore child
  241. * signal(SIGCHLD, SIG_IGN);
  242. */
  243. /* Ignore TTY */
  244. signal(SIGTSTP, SIG_IGN);
  245. signal(SIGTTOU, SIG_IGN);
  246. signal(SIGTTIN, SIG_IGN);
  247. /* Catch hangup */
  248. signal(SIGHUP, mid_signal_handler);
  249. /* Catch kill */
  250. signal(SIGTERM, mid_signal_handler);
  251. return 0;
  252. }
  253. /* Fork process */
  254. pid = fork();
  255. if (pid < 0) {
  256. MLGE("MID: Process fork failure. MID will stop as it is critical.");
  257. return -1;
  258. }
  259. if (pid > 0)
  260. exit(0);
  261. /* Change the file permissions */
  262. umask(027);
  263. /* Change to running directory */
  264. if (chdir(rdir) < 0) {
  265. MLGW("MID: Failed to change to running dir (specified in mid.conf) \"%s\". MID will run on \"/\" folder.",
  266. rdir);
  267. if (chdir("/") < 0)
  268. MLGE("MID: MID will run from current location, as chdir call failed.");
  269. }
  270. /* Open PID file */
  271. #ifndef HAVE_ANDROID_OS
  272. if (pidfile) {
  273. fd = open(pidfile, O_RDWR|O_CREAT, 0640);
  274. if (fd < 0) {
  275. MLGE("MID: MID cannot open PID file: %s. Process PID will not be recorded.", pidfile);
  276. }
  277. if (lockf(fd, F_TLOCK, 0) < 0) {
  278. close(fd);
  279. MLGE("MID: PID file %s lock failure. Process PID record could be corrupted.", pidfile);
  280. }
  281. /* Record pid to file - Failure are ignored. */
  282. sprintf(pid_str, "%d\n", getpid());
  283. if (fd >= 0) {
  284. write(fd, pid_str, strlen(pid_str));
  285. close(fd);
  286. }
  287. }
  288. #endif
  289. /* Create a new SID for the child process */
  290. sid = setsid();
  291. if (sid < 0) {
  292. MLGE("MID: Unable to get SID for child process. MID will stop as it is critical.");
  293. return -1;
  294. }
  295. close(STDIN_FILENO);
  296. close(STDOUT_FILENO);
  297. close(STDERR_FILENO);
  298. freopen("/dev/null", "r", stdin);
  299. freopen("/dev/null", "w", stdout);
  300. freopen("/dev/null", "w", stderr);
  301. /* Signal handling
  302. * Ignore child
  303. * signal(SIGCHLD, SIG_IGN);
  304. */
  305. /* Ignore TTY */
  306. signal(SIGTSTP, SIG_IGN);
  307. signal(SIGTTOU, SIG_IGN);
  308. signal(SIGTTIN, SIG_IGN);
  309. /* Catch hangup */
  310. signal(SIGHUP, mid_signal_handler);
  311. /* Catch kill */
  312. signal(SIGTERM, mid_signal_handler);
  313. return 0;
  314. }
  315. static bool get_user_id_by_user_name(const char* user_name, uid_t* uid)
  316. {
  317. struct passwd *user;
  318. if (user_name == NULL) {
  319. MLGE("No user name supplied");
  320. return false;
  321. }
  322. user = getpwnam(user_name);
  323. if (!user) {
  324. MLGE("Failed to find user \"%s\"", user_name);
  325. return false;
  326. }
  327. *uid = user->pw_uid;
  328. return true;
  329. }
  330. static bool get_group_id_by_group_name(const char* group_name, gid_t* gid)
  331. {
  332. struct group *group;
  333. if (group_name == NULL) {
  334. MLGE("No group name supplied");
  335. return false;
  336. }
  337. group = getgrnam(group_name);
  338. if (!group) {
  339. MLGE("Failed to find group \"%s\"", group_name);
  340. return false;
  341. }
  342. *gid = group->gr_gid;
  343. return true;
  344. }
  345. static bool switch_to_user_with_capabilities(const char* run_as_user, const char* run_as_group, const char* capabilities)
  346. {
  347. uid_t user_id;
  348. gid_t group_id;
  349. cap_t caps_to_set = NULL;
  350. cap_t end_caps = NULL;
  351. bool success = false;
  352. #if defined(MOTOROLA_FEATURE)
  353. gid_t gid = AID_BLUETOOTH;
  354. #endif
  355. MLGD("Switching to user \"%s\", group \"%s\" with capabilities \"%s\"", run_as_user, run_as_group, capabilities);
  356. if (!get_user_id_by_user_name(run_as_user, &user_id))
  357. goto exit;
  358. if (!get_group_id_by_group_name(run_as_group, &group_id))
  359. goto exit;
  360. caps_to_set = cap_from_text(capabilities);
  361. if (caps_to_set == NULL) {
  362. MLGE("Invalid capabilities string: \"%s\"", capabilities);
  363. goto exit;
  364. }
  365. if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) {
  366. MLGE("Failed to set PR_SET_KEEPCAPS flag: %s", strerror(errno));
  367. goto exit;
  368. }
  369. #if defined(MOTOROLA_FEATURE)
  370. // Set Bluetooth Group as this is needed to re-connect to DBUS
  371. setgroups(1, &gid);
  372. #endif
  373. if (setregid(group_id, group_id) == -1) {
  374. MLGE("Failed to set group ID of self: %s", strerror(errno));
  375. goto exit;
  376. }
  377. if (setreuid(user_id, user_id) == -1) {
  378. MLGE("Failed to set user ID of self: %s", strerror(errno));
  379. goto exit;
  380. }
  381. // Now set the caps again, since the effective set was cleared
  382. MLGD("Setting capabilities to: %s", cap_to_text(caps_to_set, 0));
  383. if(cap_set_proc(caps_to_set) == -1) {
  384. MLGE("Failed to set capabilities of self after setuid: %s", strerror(errno));
  385. goto exit;
  386. }
  387. end_caps = cap_get_proc();
  388. MLGD("End: user=%d, capabilities=\"%s\"", getuid(), cap_to_text(end_caps, 0));
  389. success = true;
  390. exit:
  391. if (caps_to_set) cap_free(caps_to_set);
  392. if (end_caps) cap_free(end_caps);
  393. return success;
  394. }
  395. static void mid_usage(void)
  396. {
  397. printf(
  398. "Usage: ./mid [options]\n"
  399. "\n"
  400. " -h, --help Display this usage information.\n"
  401. " --cfg CFG_FILE_PATH Load configuration from file. default "
  402. MID_CFG_FILE "\n"
  403. "\n"
  404. );
  405. }
  406. #if defined(MOTOROLA_FEATURE)
  407. static void* mode_checker(void *arg)
  408. {
  409. MID_State_t state = STATE_OFF;
  410. struct mid *mid_info_p = (struct mid *)arg;
  411. MLGD("mode thread: starting");
  412. while(mid_info_p) {
  413. sleep(1);
  414. if (state == mid_info_p->state)
  415. continue;
  416. state = STATE_OFF;
  417. switch(mid_info_p->state) {
  418. case STATE_BOOT:
  419. MLGD("mode thread: testing for ITP mode");
  420. if (!my_system(&mid_info, mot_mid_info.itp_mode_cmd)) {
  421. MLGI("mode thread: ITP mode detected");
  422. state = STATE_BOOT;
  423. mot_mid_info.dual_boot_mode = 1;
  424. }
  425. break;
  426. case STATE_ON:
  427. MLGD("mode thread: testing for signaling mode");
  428. if (!my_system(&mid_info, mot_mid_info.norm_mode_cmd)) {
  429. MLGI("mode thread: signaling mode detected");
  430. state = STATE_ON;
  431. }
  432. break;
  433. default:
  434. break;
  435. }
  436. }
  437. MLGD("mode thread: exiting");
  438. pthread_exit(NULL);
  439. return(NULL);
  440. }
  441. #endif
  442. #define NEXT_STATE(_state_) if (_state_!= MID_SAME_STATE) Self_p->state=_state_
  443. int main(int argc, char *argv[])
  444. {
  445. size_t i = 0;
  446. int ipc_event = 0;
  447. time_t time_entered_state;
  448. /* Configuration file */
  449. #ifdef MID_PARSE_KER_CMDLINE
  450. char *kernel_cmd_line;
  451. #define MAX_STR_SIZE 65534
  452. char garbage[MAX_STR_SIZE + 1];
  453. int cmd_line_sz = 0;
  454. int read_line_sz;
  455. int fproc;
  456. char* cfg_filename = NULL;
  457. char* pindex = NULL;
  458. #endif
  459. /* Return value */
  460. int res = 0;
  461. /* Dynamic library handle */
  462. char *dl_error = NULL;
  463. char *dl_name = NULL;
  464. /* Command line parameters */
  465. int option_index = 0;
  466. int cmd_args;
  467. /* Indicates if a kernel configuration parameter is available */
  468. int kernel_cfg = 0;
  469. enum {
  470. CFG_FILE = 1
  471. #if defined(MOTOROLA_FEATURE)
  472. , FIRM_DIR = 2
  473. #endif
  474. };
  475. struct option long_options[] = {
  476. { "help", no_argument, NULL, 'h' },
  477. { "cfg", required_argument, NULL, CFG_FILE },
  478. #if defined(MOTOROLA_FEATURE)
  479. { "firm_dir", required_argument, NULL, FIRM_DIR },
  480. #endif
  481. { 0, 0, 0, 0 }
  482. };
  483. char* cfgfile;
  484. struct mid_config* config;
  485. apr_status_t apr_status;
  486. #if defined(MOTOROLA_FEATURE)
  487. pthread_t mode_checker_td;
  488. /* Indicates that we are reconnecting to DBUS */
  489. int reconnect =0;
  490. #endif
  491. if ((apr_status = apr_app_initialize(&argc, (char const* const**)&argv, NULL)) != APR_SUCCESS) {
  492. char message[100];
  493. MLGE("MID: Failed to initialize Apache Portable Runtime: %s. This critical MID will exit now.\n",
  494. apr_strerror(apr_status, message, sizeof(message)));
  495. exit(EXIT_FAILURE);
  496. }
  497. opterr = 0;
  498. optind = 0;
  499. memset(&mid_info, 0, sizeof(struct mid));
  500. memset(&mod_firm, 0, sizeof(union mid_modem_firmware));
  501. memset(&prim_dev, 0, sizeof(struct mid_dev));
  502. memset(&sec_dev, 0, sizeof(struct mid_dev));
  503. config = calloc(1, sizeof(struct mid_config));
  504. moli_load_cfgfile = &stub_moli_load_cfgfile;
  505. moli_default_settings = &stub_moli_default_settings;
  506. mid_info.moli_configure_security_data = &stub_moli_configure_security_data;
  507. mid_info.moli_boot = &stub_moli_boot;
  508. mid_info.moli_get_crash_dump = &stub_moli_get_crash_dump;
  509. mid_info.moli_fw_upgrade_get_error_str = &stub_moli_fw_upgrade_get_error_str;
  510. mid_info.moli_fw_upgrade_flash = &stub_moli_fw_upgrade_flash;
  511. mid_info.moli_fw_upgrade_init = &stub_moli_fw_upgrade_init;
  512. mid_info.moli_fw_upgrade_status = &stub_moli_fw_upgrade_status;
  513. mid_info.moli_fw_upgrade_img_xfer = &stub_moli_fw_upgrade_img_xfer;
  514. mid_info.config = config;
  515. #ifdef DEBUG_TRACE
  516. mid_dbg_info.log_fd = NULL;
  517. #endif
  518. mid_info.pid_fd = NULL;
  519. mid_info.cfg_fd = NULL;
  520. mid_info.power_on_release = 0;
  521. #if defined(MOTOROLA_FEATURE)
  522. mot_mid_info.recovery_mode = 0;
  523. #endif
  524. mid_info.pool=NULL;
  525. if((apr_status = apr_pool_create(&mid_info.pool, NULL)) != APR_SUCCESS) {
  526. char message[100];
  527. MLGE("MID: Failed to create memory pool: %s. MID will exit now.\n",
  528. apr_strerror(apr_status, message, sizeof(message)));
  529. goto error;
  530. }
  531. /* Settings order 1) default (include files) 2) configuration file
  532. * 3) command line arguments 4) kernel command line */
  533. /* Default settings initialization */
  534. /* Daemon working dir - Firmware dir */
  535. /* Modem IDs */
  536. mid_info.modem_build_string = MODEM_BUILD_STRING;
  537. config->sec_data_file = NULL;
  538. #ifdef DEBUG_TRACE
  539. mid_dbg_info.mid_dbg_level = MID_DBG_DEFAULT_LEVEL;
  540. mid_dbg_info.logfile = MID_LOG_FILE;
  541. #endif
  542. cfgfile = MID_CFG_FILE;
  543. /* Set up default path for initial and optional secondary link */
  544. prim_dev.name = PRI_DEFAULT_PATH;
  545. sec_dev.name = SEC_DEFAULT_PATH;
  546. /* Default values for modem firmware, and link defined
  547. * in specific moli implematation
  548. */
  549. config->prim_dev_config = &prim_dev;
  550. config->sec_dev_config = &sec_dev;
  551. config->mod_firm_config = &mod_firm;
  552. MLGD("MID: ST-Ericsson Modem Init Daemon started: %s.", VERSION);
  553. mid_info.at_chnl_fd = -1;
  554. if (unlikely((apr_status = apr_thread_mutex_create(&mid_info.mutex, 0, mid_info.pool)) != APR_SUCCESS)) {
  555. char message[100];
  556. MLGE("MID: Unable to init internal mid data mutex: %s. Problems are forecasted when mutex will be used.\n",
  557. apr_strerror(apr_status, message, sizeof(message)));
  558. }
  559. mid_info.dl_handle = NULL;
  560. #ifdef PERF_MEASUREMENT
  561. if (clock_gettime(CLOCK_MONOTONIC, &mid_info.midStarted))
  562. MLGW("TIME: Error getting monotonic clock. Following time report should be considered as wrong.");
  563. float used_time;
  564. used_time = (float)(mid_info.midStarted.tv_sec+(float)(mid_info.midStarted.tv_nsec/1000000000));
  565. MLGD("TIME: Started (MONOTONIC CLOCK - clock origin is unspecified) at: %4.2f sec.",used_time);
  566. #endif
  567. #ifdef MID_PARSE_KER_CMDLINE
  568. /* Read /proc/cmdline */
  569. fproc = open("/proc/cmdline", O_RDONLY);
  570. if (fproc == -1) {
  571. kernel_cmd_line = NULL;
  572. MLGD("MID: No kernel command line accessible from /proc/cmdline.");
  573. }
  574. else {
  575. /* Count kernel cmd line size */
  576. while ((read_line_sz = read(fproc, garbage, MAX_STR_SIZE)) != 0) {
  577. if (read_line_sz == -1) {
  578. MLGE("MID: Unable to read kernel command line: %s.", strerror(errno));
  579. kernel_cmd_line = NULL;
  580. goto ker_cmdline_proc_close;
  581. }
  582. cmd_line_sz += read_line_sz;
  583. }
  584. /* Reset cmd line pointer */
  585. if (lseek(fproc, 0, SEEK_SET) == -1) {
  586. MLGE("MID: Unable to lseek position in /proc/cmdline.");
  587. kernel_cmd_line = NULL;
  588. goto ker_cmdline_proc_close;
  589. }
  590. /* Empty cmd line ? */
  591. if (cmd_line_sz == 0) {
  592. MLGE("MID: /proc/cmdline string is empty.");
  593. kernel_cmd_line = NULL;
  594. goto ker_cmdline_proc_close;
  595. }
  596. /* Add room for end of line while allocating */
  597. kernel_cmd_line = malloc((cmd_line_sz + 1) * sizeof(char));
  598. if (!kernel_cmd_line) {
  599. MLGE("MID: Unable to malloc cmd_line string.");
  600. kernel_cmd_line = NULL;
  601. goto ker_cmdline_proc_close;
  602. }
  603. if (read(fproc, kernel_cmd_line, cmd_line_sz) == -1) {
  604. MLGE("MID: Unable to read /proc/cmdline.");
  605. free(kernel_cmd_line);
  606. kernel_cmd_line = NULL;
  607. goto ker_cmdline_proc_close;
  608. }
  609. /* Find LF and trucate the string */
  610. pindex = index(kernel_cmd_line, 0x0A);
  611. if (pindex != NULL)
  612. *pindex = '\0';
  613. kernel_cmd_line[cmd_line_sz] = '\0';
  614. MLGD("MID: Success to read /proc/cmdline, get: %s.", kernel_cmd_line);
  615. }
  616. ker_cmdline_proc_close:
  617. close(fproc);
  618. /* Parse /proc/cmdline, check kernel command line parameters for a configuration file */
  619. if ((kernel_cmd_line != NULL) &&
  620. ((cfg_filename = strstr(kernel_cmd_line, CMD_PARM_NAME)) != NULL)) {
  621. /* point on '=' character */
  622. cfg_filename = index(cfg_filename, 0x3d);
  623. if (cfg_filename == NULL) {
  624. MLGE("MID: Kernel command line parse error.");
  625. free(kernel_cmd_line);
  626. goto ker_cmdline_fallback;
  627. }
  628. cfg_filename++;
  629. /* point on first white space */
  630. pindex = index(cfg_filename, 0x20);
  631. if (pindex != NULL)
  632. *pindex = '\0';
  633. /* If no white space, end of string is already marked */
  634. cfgfile=strdup(cfg_filename);
  635. MLGD("MID: Found a configuration file name on kernel command line parameters: %s.", cfgfile);
  636. kernel_cfg = 1;
  637. free(kernel_cmd_line);
  638. } else {
  639. ker_cmdline_fallback:
  640. MLGD("MID: No %s option on kernel command line. Try to check for mid --cfg option.", CMD_PARM_NAME);
  641. kernel_cfg = 0;
  642. }
  643. #endif
  644. /* Parse command line */
  645. while ((cmd_args = getopt_long_only(argc, argv, "h", long_options,
  646. &option_index)) != -1) {
  647. switch (cmd_args) {
  648. case 'h':
  649. mid_usage();
  650. exit(EXIT_SUCCESS);
  651. case CFG_FILE:
  652. if (!kernel_cfg)
  653. cfgfile = strdup(optarg);
  654. break;
  655. #if defined(MOTOROLA_FEATURE)
  656. case FIRM_DIR:
  657. /* Processed later */
  658. break;
  659. #endif
  660. default:
  661. MLGE("MID: Invalid option / parameter: %s. Will exit now.", argv[optind]);
  662. mid_usage();
  663. exit(EXIT_FAILURE);
  664. }
  665. }
  666. if (argc != optind) {
  667. int i;
  668. MLGE("MID: Too much parameter on command line: ");
  669. for (i = optind; i < argc; i++)
  670. MLGE("%s", argv[i]);
  671. MLGE("MID: Will exit now due command line parameters error.");
  672. mid_usage();
  673. exit(EXIT_FAILURE);
  674. }
  675. if (!mid_conf_load(config, cfgfile)) {
  676. goto error;
  677. }
  678. /* Shared library loading */
  679. if (strcmp(config->modem_arch, "OSMIUM") == 0) {
  680. prim_dev.flb_alloc_usb_unit = NULL;
  681. sec_dev.flb_alloc_usb_unit = NULL;
  682. dl_name = MID_MOLIU33x_NAME;
  683. }
  684. else if (strcmp(config->modem_arch, "HASSIUM") == 0)
  685. dl_name = MID_MOLIU5xx_NAME;
  686. else if (strcmp(config->modem_arch, "THORIUM") == 0) {
  687. prim_dev.flb_alloc_usb_unit = NULL;
  688. sec_dev.flb_alloc_usb_unit = NULL;
  689. dl_name = MID_MOLIU5xx_NAME;
  690. }
  691. if (dl_name != NULL) {
  692. MLGD("LIB: Loading %s library:", dl_name);
  693. mid_info.dl_handle = dlopen(dl_name, RTLD_LAZY);
  694. if (!mid_info.dl_handle) {
  695. dl_error = (char *)dlerror();
  696. MLGE("LIB: error: %s. MID will exit now.", dl_error);
  697. goto error;
  698. }
  699. moli_load_cfgfile = dlsym(mid_info.dl_handle, "moli_load_cfgfile");
  700. if ((dl_error = (char *)dlerror()) != NULL)
  701. goto error;
  702. MLGD("LIB: moli_check_cfgfile symbol loaded.");
  703. moli_default_settings = dlsym(mid_info.dl_handle, "moli_default_settings");
  704. if ((dl_error = (char *)dlerror()) != NULL)
  705. goto error;
  706. MLGD("LIB: moli_default_settings symbol loaded.");
  707. if (config->initial_enable_bootldr) {
  708. mid_info.moli_configure_security_data = dlsym(mid_info.dl_handle, "moli_configure_security_data");
  709. if ((dl_error = (char *)dlerror()) != NULL)
  710. goto error;
  711. MLGD("LIB: moli_configure_security_data symbol loaded.");
  712. mid_info.moli_boot = dlsym(mid_info.dl_handle, "moli_boot");
  713. if ((dl_error = (char *)dlerror()) != NULL)
  714. goto error;
  715. MLGD("LIB: moli_boot symbol loaded.");
  716. }
  717. if (strncmp(dl_name, MID_MOLIU5xx_NAME, strlen(MID_MOLIU5xx_NAME)) == 0) {
  718. if (config->initial_enable_bootldr) {
  719. prim_dev.flb_alloc_usb_unit = dlsym(mid_info.dl_handle, "flb_alloc_usb_unit");
  720. if ((dl_error = (char *)dlerror()) != NULL)
  721. goto error;
  722. MLGD("LIB: flb_alloc_usb_unit symbol loaded.");
  723. sec_dev.flb_alloc_usb_unit = dlsym(mid_info.dl_handle, "flb_alloc_usb_unit");
  724. if ((dl_error = (char *)dlerror()) != NULL)
  725. goto error;
  726. MLGD("LIB: flb_alloc_usb_unit symbol loaded.");
  727. } else {
  728. mid_info.moli_fw_upgrade_get_error_str = dlsym(mid_info.dl_handle, "moli_fw_upgrade_get_error_str");
  729. if ((dl_error = (char *)dlerror()) != NULL)
  730. goto error;
  731. MLGD("LIB: moli_fw_upgrade_get_error_str symbol loaded.");
  732. mid_info.moli_fw_upgrade_flash = dlsym(mid_info.dl_handle,"moli_fw_upgrade_flash");
  733. if ((dl_error = (char *)dlerror()) != NULL)
  734. goto error;
  735. MLGD("LIB: moli_fw_upgrade_flash symbol loaded.");
  736. mid_info.moli_fw_upgrade_init = dlsym(mid_info.dl_handle,"moli_fw_upgrade_init");
  737. if ((dl_error = (char *)dlerror()) != NULL)
  738. goto error;
  739. MLGD("LIB: moli_fw_upgrade_init symbol loaded.");
  740. mid_info.moli_fw_upgrade_status = dlsym(mid_info.dl_handle,"moli_fw_upgrade_status");
  741. if ((dl_error = (char *)dlerror()) != NULL)
  742. goto error;
  743. MLGD("LIB: moli_fw_upgrade_status symbol loaded.");
  744. mid_info.moli_fw_upgrade_img_xfer = dlsym(mid_info.dl_handle,"moli_fw_upgrade_img_xfer");
  745. if ((dl_error = (char *)dlerror()) != NULL)
  746. goto error;
  747. MLGD("LIB: moli_fw_upgrade_img_xfer symbol loaded.");
  748. }
  749. mid_info.moli_get_crash_dump = dlsym(mid_info.dl_handle, "moli_get_crash_dump");
  750. if ((dl_error = (char *)dlerror()) != NULL)
  751. goto error;
  752. MLGD("LIB: moli_get_crash_dump symbol loaded.");
  753. }
  754. MLGD("LIB: %s library loaded successfully.", dl_name);
  755. }
  756. moli_default_settings(&mid_info);
  757. moli_load_cfgfile(&mid_info, cfgfile);
  758. #if defined(MOTOROLA_FEATURE)
  759. /* Parse command line for --firm_dir, which overrides configuration file value for initial_rdir */
  760. optind = 0;
  761. while ((cmd_args = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1) {
  762. switch (cmd_args) {
  763. case FIRM_DIR:
  764. config->initial_rdir = malloc((strlen(optarg) + 1) * sizeof(char));
  765. if (config->initial_rdir == NULL) {
  766. MLGE("Unable to allocate internal mid initial_rdir: %s. Will exit now.", strerror(errno));
  767. if (mid_info.dl_handle != NULL)
  768. dlclose(mid_info.dl_handle);
  769. exit(EXIT_FAILURE);
  770. }
  771. strncpy(config->initial_rdir, optarg, strlen(optarg));
  772. config->initial_rdir[strlen(optarg)] = '\0';
  773. /* --firm_dir option is only used in recovery mode for Motorola devices. */
  774. /* Use this as an indication to handle specific needs in recovery mode. */
  775. MLGE("Using config->initial_rdir: '%s' for recovery mode", config->initial_rdir);
  776. mot_mid_info.recovery_mode = 1;
  777. config->mod_prefl_cmd = mot_mid_info.recovery_mod_prefl_cmd;
  778. break;
  779. }
  780. }
  781. if (argc != optind) {
  782. int i;
  783. MLGE("Invalid parameter: ");
  784. for (i = optind; i < argc; i++)
  785. MLGE("%s. Will exit now.", argv[i]);
  786. mid_usage();
  787. if (mid_info.dl_handle != NULL)
  788. dlclose(mid_info.dl_handle);
  789. exit(EXIT_FAILURE);
  790. }
  791. #endif /* MOTOROLA_FEATURE */
  792. mid_info.mfa = mid_mfa_init(&mid_info, mid_info.config, mid_info.pool);
  793. /* One-shot configuration */
  794. (void)my_system(&mid_info, mid_info.config->mod_init_cmd);
  795. if (config->daemonize) {
  796. if (daemonize(config->initial_rdir, config->pidfile)) {
  797. MLGE("MID: Daemonization error. Will exit now.");
  798. if (mid_info.dl_handle != NULL)
  799. dlclose(mid_info.dl_handle);
  800. exit(EXIT_FAILURE);
  801. }
  802. } else {
  803. /* Change to running directory */
  804. if (chdir(config->initial_rdir) < 0) {
  805. MLGW("MID: Failed to change to running dir \"%s\". MID will run on \"/\" folder.",
  806. config->initial_rdir);
  807. if (chdir("/") < 0)
  808. MLGE("MID: MID will run from current location.");
  809. }
  810. /* Catch hangup */
  811. signal(SIGHUP, mid_signal_handler);
  812. /* Catch kill */
  813. signal(SIGTERM, mid_signal_handler);
  814. }
  815. #ifndef HAVE_ANDROID_OS
  816. #ifdef DEBUG_TRACE
  817. if (mid_dbg_info.logfile && mid_dbg_info.log_to_file) {
  818. mid_dbg_info.log_fd = fopen(mid_dbg_info.logfile, "w");
  819. if (mid_dbg_info.log_fd == NULL) {
  820. MLGE("MID: Log file open failure: %s, %s. Will exit now.", mid_dbg_info.logfile, strerror(errno));
  821. if (mid_info.dl_handle != NULL)
  822. dlclose(mid_info.dl_handle);
  823. exit(EXIT_FAILURE);
  824. }
  825. }
  826. #endif
  827. #endif
  828. mid_info.mid_power = mid_power_init();
  829. if (mid_info.mid_power == NULL) {
  830. MLGE("Failed to initialize power subsystem");
  831. goto error;
  832. }
  833. MLGD("MID: Modem_ARCH:%d %s | Modem_Build:(pending...)", mid_info.config->modem_arch_id, mid_info.config->modem_arch);
  834. /* Remove end "/" in directory name (if any) */
  835. cleanupdirname(&mid_info);
  836. /* Ensure service gpio is released */
  837. mid_enable_gpio_service_safe_mode(&mid_info);
  838. /* Request GPIOs */
  839. mid_info.gpios = mid_gpio_init(mid_info.config->mid_gpios, mid_info.config->gpio_base_path, mid_info.config->gpio_ctrl, mid_info.config->gpio_no_aclow, mid_info.config->gpio_no_xport, mid_info.config->gpio_no_dir);
  840. if (mid_info.gpios == NULL) {
  841. MLGE("GPIO: Unable to init GPIOs. This is critical, MID will exit now.");
  842. state_all_evt_sig_kill(&mid_info);
  843. if (mid_info.dl_handle != NULL)
  844. dlclose(mid_info.dl_handle);
  845. goto error;
  846. }
  847. /* Connect IPC */
  848. res = -EMID;
  849. MLGD("DBUS: Connecting to DBUS... (looping to connect)");
  850. while (res != 0) {
  851. #if defined(MOTOROLA_FEATURE)
  852. res = ipc_medium_connect(&mid_info,reconnect);
  853. #else
  854. res = ipc_medium_connect(&mid_info);
  855. #endif
  856. if (res != 0)
  857. usleep(MID_IPC_OPS_DELAY);
  858. };
  859. MLGD("DBUS: Connected to DBUS.");
  860. #if defined(MOTOROLA_FEATURE)
  861. if (mot_mid_info.recovery_mode == 0) {
  862. #endif
  863. // Now that all modules got their chance to initialize, we can drop
  864. // all privileges not needed during normal operations.
  865. if (!switch_to_user_with_capabilities("system", "radio", "CAP_SYS_MODULE,CAP_NET_RAW,CAP_NET_ADMIN,CAP_SYS_BOOT=ep")) {
  866. MLGE("Failed to drop privileges");
  867. goto error;
  868. }
  869. #if defined(MOTOROLA_FEATURE)
  870. }
  871. #endif
  872. #if defined(MOTOROLA_FEATURE)
  873. if (strncmp("service", mid_info.config->runtime_mode, strlen("service")) != 0) {
  874. #endif
  875. /* Initial startup trig a modem start event */
  876. MLGD("STMACH: MID_MODEM_START_EVT event set");
  877. SET_FLAG(mid_info.event, MID_MODEM_START_EVT);
  878. #if defined(MOTOROLA_FEATURE)
  879. }
  880. #endif
  881. mid_disable_gpio_out_safe_mode(&mid_info);
  882. /* Ensure modem is off */
  883. /* TODO check if an AT channel can be openned to shutdown */
  884. shutdown_modem(&mid_info);
  885. /* Set all ios in safe mode */
  886. mid_enable_io_safe_mode(&mid_info);
  887. /* Initial state */
  888. mid_info.state = STATE_OFF;
  889. time_entered_state = time(NULL);
  890. mid_info.flash_retry_left = mid_info.config->flash_retry;
  891. mid_info.boot_retry_left = mid_info.config->boot_retry;
  892. mid_info.shutdown_retry_left = mid_info.config->shutdown_retry;
  893. mid_info.boot_failed = 0;
  894. mid_info.flash_failed = 0;
  895. mid_info.modem_warm_start = 0;
  896. mid_info.moli_fw_upgrade_init(&mid_info.fw_upgr_last_error);
  897. #if defined(MOTOROLA_FEATURE)
  898. res = pthread_create(&mode_checker_td, NULL, &mode_checker, (void*)&mid_info);
  899. #endif
  900. /* Poll filedescriptor */
  901. for (;;) {
  902. const size_t guessed_num_fds = ipc_get_num_fds() + 3;
  903. apr_pollfd_t fds[guessed_num_fds];
  904. size_t num_fds;
  905. size_t num_ipc_fds;
  906. apr_file_t* rst2_fd;
  907. apr_file_t* pwrrstin_fd;
  908. bool has_mfa_fd;
  909. apr_status_t status;
  910. apr_int32_t num_signalled;
  911. char message[100];
  912. LOCK_MID_DATA;
  913. num_fds = num_ipc_fds = ipc_get_fds(fds, guessed_num_fds - 3);
  914. rst2_fd = mid_gpio_get_fd(mid_info.gpios, GPIO_ID_RESOUT2);
  915. pwrrstin_fd = mid_gpio_get_fd(mid_info.gpios, GPIO_ID_PWRRSTIN);
  916. if (rst2_fd != NULL) {
  917. fds[num_fds].desc_type = APR_POLL_FILE;
  918. fds[num_fds].desc.f = rst2_fd;
  919. fds[num_fds].reqevents = APR_POLLPRI;
  920. fds[num_fds].rtnevents = 0;
  921. num_fds++;
  922. }
  923. if (pwrrstin_fd != NULL) {
  924. fds[num_fds].desc_type = APR_POLL_FILE;
  925. fds[num_fds].desc.f = pwrrstin_fd;
  926. fds[num_fds].reqevents = APR_POLLPRI;
  927. fds[num_fds].rtnevents = 0;
  928. num_fds++;
  929. }
  930. if ((has_mfa_fd = mid_mfa_get_fd(mid_info.mfa, &fds[num_fds]))) {
  931. num_fds++;
  932. }
  933. UNLOCK_MID_DATA;
  934. /* If we're in a none transient state we allow sleep */
  935. if (!mid_statemachine_get_current_timeout(&mid_info))
  936. if (!mid_permit_suspend(mid_info.mid_power))
  937. MLGE("POW: Unable to allow system to suspend. MID will continue anyway but system power management may be disturbed.");
  938. /* Poll */
  939. status = apr_poll(fds, num_fds, &num_signalled, MID_POLL_LAT * 1000000);
  940. switch(status) {
  941. case APR_EINTR:
  942. MLGI("MID: Received interrupt condition while polling: %s. MID will process events that are set.", apr_strerror(status, message, sizeof(message)));
  943. break;
  944. case APR_TIMEUP:
  945. /* Here we check if we have a timeout on the POLL, that we don't have */
  946. /* any pending event, we are in a transient state and that we exceeded */
  947. /* time in the current state. This indicates that we are in some deadlock */
  948. /* and that we will try to recover. */
  949. if ((time(NULL) > time_entered_state + mid_statemachine_get_current_timeout(&mid_info)) &&
  950. mid_statemachine_get_current_timeout(&mid_info) > 0) {
  951. MLGE("MID: MID in state (%s) and maximum time in this state is exceeded.", mid_statemachine_get_name_of_current_state(&mid_info));
  952. LOCK_MID_DATA;
  953. MLGE("STMACH: MID_TIMEOUT_EVT event set.");
  954. SET_FLAG(mid_info.event, MID_TIMEOUT_EVT);
  955. UNLOCK_MID_DATA;
  956. }
  957. break;
  958. case APR_SUCCESS:
  959. MLGD("MID: Received event(s) on monitored file descriptor(s). MID will check event(s) source(s)");
  960. for (i = 0; i < num_ipc_fds; i++) {
  961. if (fds[i].rtnevents) {
  962. #if defined(MOTOROLA_FEATURE)
  963. if (fds[i].rtnevents & APR_POLLHUP)
  964. {
  965. MLGD("MID: DBUS HANG UP event received");
  966. // Clean up and Re-connect to DBUS
  967. ipc_medium_cleanup();
  968. // Wait for a second and then re-connect to DBUS
  969. usleep(MID_IPC_OPS_DELAY);
  970. usleep(MID_IPC_OPS_DELAY);
  971. /* Re-Connect IPC */
  972. reconnect = 1;
  973. res = -EMID;
  974. MLGD("DBUS: Re-Connecting to DBUS... (looping to connect)");
  975. while (res != 0) {
  976. res = ipc_medium_connect(&mid_info,reconnect);
  977. if (res != 0)
  978. usleep(MID_IPC_OPS_DELAY);
  979. }
  980. ipc_event = 0;
  981. }
  982. else
  983. #endif
  984. {
  985. MLGD("MID: DBUS activity received.");
  986. ipc_notify_for_event(i, fds[i].rtnevents);
  987. ipc_event = 1;
  988. }
  989. }
  990. }
  991. if (ipc_event) {
  992. if (!mid_prevent_suspend(mid_info.mid_power))
  993. MLGE("POW: Unable to prevent system to suspend. MID will continue anyway but power management may disturbe MID operation.");
  994. ipc_process_event();
  995. ipc_event = 0;
  996. }
  997. if (rst2_fd != NULL) {
  998. if (fds[i].rtnevents & APR_POLLPRI) {
  999. int status;
  1000. MLGD("MID: GPIO RESOUT2 activity received.");
  1001. status = mid_gpio_get_value(mid_info.gpios, GPIO_ID_RESOUT2);
  1002. LOCK_MID_DATA;
  1003. MLGD("STMACH: MID_GPIO_RST2_EVT event set.");
  1004. SET_FLAG(mid_info.event, MID_GPIO_RST2_EVT);
  1005. UNLOCK_MID_DATA;
  1006. MLGD("GPIO: New GPIO RESOUT2 logical level (1 active, 0 inactive) %d.", status);
  1007. }
  1008. i++;
  1009. }
  1010. if (pwrrstin_fd != NULL) {
  1011. if (fds[i].rtnevents & APR_POLLPRI) {
  1012. int status;
  1013. MLGD("MID: GPIO PWRRSTIN activity received.");
  1014. status = mid_gpio_get_value(mid_info.gpios, GPIO_ID_PWRRSTIN);
  1015. LOCK_MID_DATA;
  1016. MLGD("STMACH: MID_GPIO_PRST_EVT event set.");
  1017. SET_FLAG(mid_info.event, MID_GPIO_PRST_EVT);
  1018. UNLOCK_MID_DATA;
  1019. MLGD("GPIO: New GPIO PWRRSTIN logical level (1 active, 0 inactive) %d.", status);
  1020. }
  1021. i++;
  1022. }
  1023. if (has_mfa_fd) {
  1024. mid_mfa_receive_message(&fds[i], &mid_info, mid_info.mfa);
  1025. i++;
  1026. }
  1027. break;
  1028. default:
  1029. MLGE("MID: Poll listening problem: %s, This error is ignored and MID will continue anyway. Unexpected various error could occur from now.", apr_strerror(status, message, sizeof(message)));
  1030. break;
  1031. }
  1032. /* Process all events */
  1033. mid_statemachine_process_all_events(&mid_info, &time_entered_state);
  1034. }
  1035. if (mid_info.dl_handle != NULL)
  1036. dlclose(mid_info.dl_handle);
  1037. exit(EXIT_SUCCESS);
  1038. error:
  1039. MLGE("MID: MID will exit due to earlier error");
  1040. if (mid_info.dl_handle != NULL)
  1041. dlclose(mid_info.dl_handle);
  1042. exit(EXIT_FAILURE);
  1043. }