| /****************************************************************************** |
| *(C) Copyright 2008 Marvell International Ltd. |
| * All Rights Reserved |
| ******************************************************************************/ |
| /*-------------------------------------------------------------------------------------------------------------------- |
| * ------------------------------------------------------------------------------------------------------------------- |
| * |
| * Filename: eeh_main.c |
| * |
| * Description: The main task to process error & exception of system. |
| * |
| * History: |
| * May, 2008 - Rovin Yu Creation of file |
| * |
| * Notes: |
| * |
| ******************************************************************************/ |
| |
| /****************************************************************************** |
| * Include files |
| ******************************************************************************/ |
| #include <stdio.h> |
| #include <string.h> |
| #include <unistd.h> |
| #include <signal.h> |
| #include <termios.h> |
| #include <fcntl.h> |
| #include <stdlib.h> |
| |
| #if defined (BIONIC) |
| #include <sys/capability.h> |
| #include <sys/prctl.h> |
| #include <private/android_filesystem_config.h> |
| #endif |
| |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| |
| #include "utilities.h" |
| #include "paths_defs.h" |
| #include "pxa_dbg.h" |
| #include "eeh.h" |
| #include "EEHandler_config.h" |
| #include "eeh_assert_notify.h" |
| |
| #include "diag_al.h" |
| #define EEH_LOG_TAG "EEH" |
| |
| //DPRINTF causes for "Entry not found sys.telephony.default.loglevel" |
| #undef DPRINTF |
| #define DPRINTF printf |
| |
| int nanosleep(const struct timespec *requested_time, struct timespec *remaining); |
| |
| int InProduction_Mode(void); |
| extern void switchUser(); |
| |
| static void print_usage() |
| { |
| printf( "Error & Exception Handler Task\n" |
| "CopyRight (c) 2015 Marvell \n" |
| "Usage: eeh [-h/H] [-p] [-C k v] [-c ..] [-m ..] [-T ..]\n" |
| "Options:\n" |
| "\t-p print current EEH CFG-properties\n" |
| "\t-C keyNo Val CFG set EEH property for keyNo with Value\n" |
| "\t-c c/s/d configPROFILE: cpsr / stallCP / default-factory\n" |
| "\t-e prop2cfg update new property to run-EEH-RAM-cfg (or send text)\n" |
| "\t-m 3/4/r modem switch to 3:LTG or 4:LWG or r:reset(noAssert)\n" |
| "\t-T CPASSERT txt Test CP assert force to RAMDUMP with optional 1-word-desc\n" |
| "\t-T cpassert Test CP assert according to configuration\n" |
| "\t-T sig11/panic Test AP: sig11 or panic \n" |
| "\t-T panic txt Test AP panic with given 1word-description\n" |
| ); |
| } |
| |
| static void handle_arg(int argc, char * argv[] ) |
| { |
| int i; |
| char * cp, opt; |
| FILE *fd; |
| long *pid; |
| |
| for (i = 1; i < argc; i++) |
| { |
| cp = argv[i]; |
| if (*cp == '-') |
| { |
| opt = *(++cp); |
| |
| switch (opt) |
| { |
| // Legacy. meanwhile reserved for backward compatibility |
| case 'D': |
| case 'M': |
| break; |
| |
| case 'p': //Lower 'p': print properties only |
| eehPropGet(); |
| exit(0); |
| break; |
| |
| case 'C': //update requested property |
| int keyNo, Val; |
| if ((i + 2) >= argc) { |
| goto wrong_argument; |
| } |
| keyNo = atoi(argv[++i]); |
| Val = atoi(argv[++i]); |
| eehPropSet(keyNo, Val); |
| exit(0); |
| break; |
| |
| case 'c': //update requested property |
| i++; |
| if (i >= argc) |
| goto wrong_argument; |
| else |
| if (argv[i][0] == 'c') |
| eehConfigCpsr(); |
| else |
| if (argv[i][0] == 's') |
| eehConfig_cpStall(/*logLvl=*/7); //see eeh_HowToConfig.txt |
| else |
| if (argv[i][0] == 'd') |
| eehConfigFactoryDefault(); |
| else |
| goto wrong_argument; |
| exit(0); |
| break; |
| |
| case 'e': |
| if (argc != 3) |
| goto wrong_argument; |
| i++; |
| if (!strcmp(argv[i], "prop2cfg")) |
| eeh_cfg_prop2cfg(); |
| else |
| eeh_message2eeh(argv[i]); |
| exit(0); |
| break; |
| |
| case 'm': |
| if (argc != 3) |
| goto wrong_argument; |
| i++; |
| if (eeh_switch_modem(argv[i])) |
| goto wrong_argument; |
| exit(0); |
| break; |
| |
| case 'T': |
| if (argc > 4) |
| goto wrong_argument; |
| i++; |
| if (argv[i][0] == 'C') { //CPASSERT |
| eeh_cfg_CPSR_dis(); |
| usleep(11000); //yield for exec |
| //CPASSERT txt or CPASSERT_txt |
| if ((argc == 4) || (argv[i][8] == '_')){ |
| char buf[EEH_EXTRA_DESC_SZ]; |
| if (argc == 4) |
| snprintf(buf, EEH_EXTRA_DESC_SZ, EEH_CPASSERT_DESC "%s", argv[++i]); |
| else |
| snprintf(buf, EEH_EXTRA_DESC_SZ, EEH_CPASSERT_DESC "%s", &argv[i][9]); |
| buf[EEH_EXTRA_DESC_SZ-1] = 0; |
| eeh_message2eeh(buf); |
| usleep(11000); //yield for exec |
| } |
| fd = fopen("/dev/acipc", "w"); |
| fprintf(fd, "a") ; |
| fclose(fd); |
| } |
| else |
| if (argv[i][0] == 'c') { //cpassert |
| fd = fopen("/dev/acipc", "w"); |
| fprintf(fd, "a") ; |
| fclose(fd); |
| } |
| else |
| if (argv[i][0] == 's') { //sig11 |
| system("killall -11 diag"); |
| } |
| else |
| if (argv[i][0] == 'p') { // panic |
| const char *txt = " "; |
| |
| if (argc == 4) |
| txt = argv[++i]; |
| fd = fopen("/dev/ramdump_ctl", "w"); |
| fprintf(fd, "p_%s\n", txt); |
| fclose(fd); |
| } |
| else |
| goto wrong_argument; |
| exit(0); |
| break; |
| |
| case 'H': |
| print_usage(); |
| system("cat " TEL_DIR "eeh_HowToConfig.txt"); |
| exit(0); |
| break; |
| |
| case '?': |
| case 'h': |
| print_usage(); |
| exit(0); |
| break; |
| |
| default: |
| goto wrong_argument; |
| } // end switch |
| } // end if(-X) |
| } // end for(pass over argc) |
| return; |
| |
| wrong_argument: |
| DPRINTF("\tNot enough or wrong argument\n"); |
| print_usage(); |
| exit(-1); |
| } |
| |
| #if defined (BIONIC) |
| /* |
| * Switches UID to system, preserving following capabilities |
| * CAP_NET_RAW: create socket |
| * CAP_FOWNER/CAP_DAC_OVERRIDE/CAP_DAC_READ_SEARCH: enable diag to sdcard |
| * CAP_SYS_TIME : enable set RTC |
| * CAP_NET_ADMIN: enable config usb0 interface |
| * CAP_SYS_BOOT: enable reboot device |
| * CAP_IPC_LOCK/CAP_SYS_ADMIN: to use security service |
| */ |
| void switchUser() |
| { |
| /* add extra groups: |
| * AID_LOG to read system logs |
| */ |
| gid_t groups[] = {AID_LOG}; |
| |
| prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0); |
| setgroups(sizeof(groups)/sizeof(groups[0]), groups); |
| setgid(AID_SYSTEM); |
| setuid(AID_SYSTEM); |
| |
| struct __user_cap_header_struct header; |
| struct __user_cap_data_struct cap; |
| header.version = _LINUX_CAPABILITY_VERSION; |
| header.pid = 0; |
| cap.effective = cap.permitted = ((1 << CAP_NET_RAW) | (1 << CAP_FOWNER) | (1 << CAP_DAC_OVERRIDE) | (1 << CAP_DAC_READ_SEARCH) | (1 << CAP_SYS_TIME) |
| | (1 << CAP_NET_ADMIN) | (1 << CAP_SYS_BOOT) | (1 << CAP_SETUID) | (1 << CAP_IPC_LOCK) | (1 << CAP_SYS_ADMIN)); |
| cap.inheritable = 0; |
| capset(&header, &cap); |
| |
| /* |
| * setuid/setgid will clear the dumpable flag |
| * set it explicitly to allow debuggerd dump tombstones |
| */ |
| prctl(PR_SET_DUMPABLE, 1, 0, 0, 0); |
| } |
| #endif |
| |
| |
| /* main function */ |
| int main(int argc, char *argv[]) |
| { |
| int TelOk; |
| FILE *fd; |
| int trycount = 0; |
| #if defined (BIONIC) |
| /* |
| * change the umask before dropping root permission |
| * In Jelly Bean, init process change the default umask to 0077 |
| * which may cause some permission issues |
| */ |
| umask(0000); |
| |
| /* switch user to system in GUI mode */ |
| if(InProduction_Mode() != 2) //2 == production mode |
| switchUser(); |
| #endif |
| |
| /* |
| * handle passing in arguments |
| */ |
| handle_arg(argc, argv); |
| set_log_tag(EEH_LOG_TAG); |
| set_process_tag(); |
| |
| if (EehInit(1) != EEH_SUCCESS) |
| exit(-1); //error printed by EehInit() |
| |
| #ifndef NODIAG |
| diag_client_init(); |
| //DPRINTF("diag_client_init complete\n"); |
| #endif |
| |
| /* "delayed" extra initializations */ |
| //sleep(2); |
| /* "prepare in advance" depricated since no real usage found |
| eeh_ap_thread_info(0); //prepare "in advance" |
| */ |
| //sleep(10); |
| |
| |
| do { |
| TelOk = !access(TEL_OK_FILE, F_OK); |
| if (TelOk) { |
| //ERRMSG("Telephony seems OK\n"); |
| break; |
| } |
| else { |
| ERRMSG("check atcmdsrv_ok file\n"); |
| sleep(1); |
| } |
| }while(trycount++ < 12); |
| |
| weh_init(0); |
| |
| sleep(10); |
| eeh_journal_update_and_cut(); |
| if (eeh_sd_card_available(1) && access(LOG_DIR_SD_LOG, F_OK) != 0) |
| mkdir(LOG_DIR_SD_LOG, 0777); |
| |
| if (!TelOk && access(TEL_OK_FILE, F_OK)) { |
| ERRMSG("Telephony seems NOT OK or FAILED\n"); |
| /* Special debug to catch "CP not fully started". |
| * Keep default "heart_bit_sec=0", enable manually for the debug only |
| */ |
| if (eehCfg.heart_bit_sec) { |
| fd = fopen("/dev/ramdump_ctl", "w"); |
| fprintf(fd, "p_TelephonyNotOK_gotoPanic") ; |
| fclose(fd); |
| } |
| } |
| |
| /* Keep the thread but Sleep enough to save power */ |
| for (;; ) |
| sleep(24 * 60 * 60); |
| |
| return 0; |
| } |
| |