blob: e3f1edb226a998861d7fe6ec6621bee3c325a992 [file] [log] [blame]
/******************************************************************************
*(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;
}