//-------------------------------------------------------------------------------------------------- static void OnTransactionTimeout ( le_timer_Ref_t timerRef ///< The timer that expired. ) //-------------------------------------------------------------------------------------------------- { // Extract the iterator reference out of the timer object. Then perform a sanity check to make // sure everything is going to plan. ni_IteratorRef_t iteratorRef = (ni_IteratorRef_t)le_timer_GetContextPtr(timerRef); LE_ASSERT(iteratorRef->timerRef == timerRef); // For clearer message reporting, figure out if this is a read or write transaction. char* iterTypePtr = "Read"; if (ni_IsWriteable(iteratorRef)) { iterTypePtr = "Write"; } if (iteratorRef->isTerminated) { LE_DEBUG("Previously terminated iterator, <%p> timed out.", iteratorRef); return; } // Report the failure in the log, and close the client session. Once the session is closed all // of that user's resources within the configTree will be naturally cleaned up. LE_EMERG("%s transaction <%p> timer expired, for user %s, <%d>.", iterTypePtr, iteratorRef->reference, tu_GetUserName(iteratorRef->userRef), tu_GetUserId(iteratorRef->userRef)); tu_TerminateConfigClient(iteratorRef->sessionRef, "Transaction timeout."); }
//-------------------------------------------------------------------------------------------------- le_result_t fwDaemons_SigChildHandler ( pid_t pid, ///< [IN] Pid of the process that produced the SIGCHLD. int status ///< [IN] Status of the process. ) { // See which daemon produced this signal. DaemonObj_t* daemonObjPtr = NULL; int i; for (i = 0; i < NUM_ARRAY_MEMBERS(FrameworkDaemons); i++) { if (FrameworkDaemons[i].pid == pid) { daemonObjPtr = &(FrameworkDaemons[i]); // Check status of process and handle SIGCONT and SIGSTOP signals. if ( WIFSTOPPED(status) || WIFCONTINUED(status) ) { // The framework dameon was either stopped or continued which should not happen kill // the process now. kill_Hard(pid); // Return LE_OK here, when the process actually dies we'll get another SIGCHLD. return LE_OK; } // Mark this daemon as dead. daemonObjPtr->pid = -1; kill_Died(pid); break; } } if (daemonObjPtr == NULL) { return LE_NOT_FOUND; } if (ShutdownIndex >= 0) { // We are in the midst of a shutdown sequence, continue the shutdown sequence. ShutdownIndex = ShutdownNextDaemon(ShutdownIndex); return LE_OK; } else { // This was an unexpected error from one of the framework daemons. LE_EMERG("The framework daemon '%s' has experienced a problem.", le_path_GetBasenamePtr(daemonObjPtr->path, "/")); return LE_FAULT; } }
//---------------------------------------------------------------------------------------------- static void CheckGuardBands ( MemBlock_t* blockHeaderPtr // Pointer to the per-block overhead area of the memory block. ) { int i; // There's a guard band at the start of the data section. uint32_t* guardBandWordPtr = (uint32_t*)(blockHeaderPtr->data); for (i = 0; i < NUM_GUARD_BAND_WORDS; i++, guardBandWordPtr++) { if (*guardBandWordPtr != GUARD_WORD) { LE_EMERG("Memory corruption detected at address %p before object allocated" " from pool '%s'.", guardBandWordPtr, blockHeaderPtr->poolPtr->name); LE_FATAL("Guard band value should have been %d, but was found to be %d.", GUARD_WORD, *guardBandWordPtr); } } // There's another guard band at the end of the data section. guardBandWordPtr = (uint32_t*)( ((uint8_t*)blockHeaderPtr) + blockHeaderPtr->poolPtr->blockSize - GUARD_BAND_SIZE); for (i = 0; i < NUM_GUARD_BAND_WORDS; i++, guardBandWordPtr++) { if (*guardBandWordPtr != GUARD_WORD) { LE_EMERG("Memory corruption detected at address %p at end of object allocated" " from pool '%s'.", guardBandWordPtr, blockHeaderPtr->poolPtr->name); LE_FATAL("Guard band value should have been %d, but was found to be %d.", GUARD_WORD, *guardBandWordPtr); } } }
//-------------------------------------------------------------------------------------------------- void comp1_Foo(void) { LE_DEBUG("comp1 %d msg", LE_LOG_DEBUG); LE_INFO("comp1 %d msg", LE_LOG_INFO); LE_WARN("comp1 %d msg", LE_LOG_WARN); LE_ERROR("comp1 %d msg", LE_LOG_ERR); LE_CRIT("comp1 %d msg", LE_LOG_CRIT); LE_EMERG("comp1 %d msg", LE_LOG_EMERG); le_log_TraceRef_t trace1 = le_log_GetTraceRef("key 1"); le_log_TraceRef_t trace2 = le_log_GetTraceRef("key 2"); LE_TRACE(trace1, "Trace msg in %s", STRINGIZE(LE_COMPONENT_NAME)); LE_TRACE(trace2, "Trace msg in %s", STRINGIZE(LE_COMPONENT_NAME)); }
//-------------------------------------------------------------------------------------------------- void tu_TerminateConfigAdminClient ( le_msg_SessionRef_t sessionRef, ///< [IN] The session that needs to close. const char* killMessage ///< [IN] The reason the session needs to close. ) //-------------------------------------------------------------------------------------------------- { tu_UserRef_t userRef = GetUserInfo(sessionRef, NULL); LE_EMERG("A fatal error occured. Killing admin sesssion <%p> for user %s, <%u>. Reason: %s", sessionRef, tu_GetUserName(userRef), tu_GetUserId(userRef), killMessage); le_msg_CloseSession(sessionRef); }
//-------------------------------------------------------------------------------------------------- static void LoadSimFromSecStore ( le_sim_Id_t simId ) { uint32_t attemptCounter = SECSTORE_ATTEMPT_MAX; le_result_t result; le_sim_States_t simState; LE_DEBUG("Start reading SIM-%d information in secure storage",simId); do { simState = le_sim_GetState(simId); switch (simState) { case LE_SIM_INSERTED: { // Set the secure storage path for the SIM char secStorePath[LE_SECSTORE_MAX_NAME_BYTES]; snprintf(secStorePath, sizeof(secStorePath), "%s/%d/%s", SECSTORE_NODE_SIM, simId, SECSTORE_NODE_PIN); char simPin[LE_SIM_PIN_MAX_BYTES] = {0}; size_t simSize = LE_SIM_PIN_MAX_BYTES; // Read PIN code stored in secure storage result = le_secStore_Read(secStorePath, (uint8_t *)simPin, &simSize); if (LE_NOT_FOUND == result) { LE_ERROR("SIM PIN code isn't found in the secure storage"); return; } else if (LE_OVERFLOW == result) { LE_WARN("PIN string too large for SIM-%d", simId); return; } else if (LE_OK != result) { LE_ERROR("Unable to retrieve PIN for SIM-%d, error %s", simId, LE_RESULT_TXT(result)); return; } if (0 == strncmp(simPin, "", sizeof(simPin))) { LE_WARN("PIN not set for SIM-%d", simId); return; } if (LE_OK != (result = le_sim_EnterPIN(simId, simPin))) { LE_ERROR("Error.%d Failed to enter SIM pin for SIM-%d", result, simId); return; } LE_DEBUG("Sim-%d is unlocked", simId); attemptCounter = 1; break; } case LE_SIM_BLOCKED: { LE_EMERG("Be careful the sim-%d is BLOCKED, need to enter PUK code",simId); attemptCounter = 1; break; } case LE_SIM_BUSY: if (attemptCounter==1) { LE_WARN("Could not load the configuration because " "the SIM is still busy after %d attempts", SECSTORE_ATTEMPT_MAX); } else { LE_WARN("Sim-%d was busy when loading configuration," "retry in 1 seconds",simId); } sleep(1); // Retry in 1 second. break; case LE_SIM_READY: LE_DEBUG("Sim-%d is ready",simId); attemptCounter = 1; break; case LE_SIM_ABSENT: LE_WARN("Sim-%d is absent",simId); attemptCounter = 1; break; case LE_SIM_POWER_DOWN: LE_WARN("Sim-%d is powered down",simId); break; case LE_SIM_STATE_UNKNOWN: break; } } while (--attemptCounter); LE_DEBUG("Load SIM information is done"); }
//-------------------------------------------------------------------------------------------------- void le_mem_Release ( void* objPtr ///< [IN] Pointer to the object to be released. ) { MemBlock_t* blockPtr; // Get the block from the object pointer. #ifdef USE_GUARD_BAND uint8_t* dataPtr = objPtr; dataPtr -= GUARD_BAND_SIZE; blockPtr = CONTAINER_OF(dataPtr, MemBlock_t, data); #else blockPtr = CONTAINER_OF(objPtr, MemBlock_t, data); #endif #ifdef USE_GUARD_BAND CheckGuardBands(blockPtr); #endif Lock(); switch (blockPtr->refCount) { case 1: { MemPool_t* poolPtr = blockPtr->poolPtr; // The reference count has reached zero. blockPtr->refCount = 0; // Call the destructor, if there is one. if (poolPtr->destructor) { // Make sure that the destructor is not called with the mutex locked, because // it is not a recursive mutex and therefore will deadlock if locked again by // the same thread. Also, fetch the destructor function address before unlocking // the mutex so that we don't touch the pool object while the mutex is unlocked. le_mem_Destructor_t destructor = poolPtr->destructor; Unlock(); destructor(objPtr); // Re-lock the mutex now so that it is safe to access the pool object again. Lock(); } #ifndef LE_MEM_VALGRIND // Release the memory back into the pool. // Note that we don't do this before calling the destructor because the destructor // still needs to access it, but after it goes back on the free list, it could get // reallocated by another thread (or even the destructor itself) and have its // contents clobbered. le_sls_Stack(&(poolPtr->freeList), &(blockPtr->link)); #else free(blockPtr); #endif poolPtr->numBlocksInUse--; break; } case 0: LE_EMERG("Releasing free block."); LE_FATAL("Free block released from pool %p (%s).", blockPtr->poolPtr, blockPtr->poolPtr->name); default: blockPtr->refCount--; } Unlock(); }
//-------------------------------------------------------------------------------------------------- static void ReadMeta ( void ) { /* Copy the meta file from sfs to a temporary location for faster access. */ char tmpFilePath[SECSTOREADMIN_MAX_PATH_BYTES] = "/tmp/tempMetaFile_secStoreTool_Deleteme"; le_result_t result = secStoreAdmin_CopyMetaTo(tmpFilePath); if (result != LE_OK) { LE_EMERG("Could not copy the meta file to path %s. Result code %s.", tmpFilePath, LE_RESULT_TXT(result)); /* Delete the temp file. */ if (unlink(tmpFilePath) != 0) { INTERNAL_ERR("Could not delete %s. %m.", tmpFilePath); } InternalErr(); } /* Open the temp file. */ FILE* tmpFilePtr; do { tmpFilePtr = fopen(tmpFilePath, "r"); } while ( (tmpFilePtr == NULL) && (errno == EINTR) ); if (tmpFilePtr == NULL) { LE_EMERG("Could not open temp file %s. %m.", tmpFilePath); /* Delete the temp file. */ if (unlink(tmpFilePath) != 0) { INTERNAL_ERR("Could not delete %s. %m.", tmpFilePath); } InternalErr(); } /* Read the temp file. */ // Buffer to store a line read from a meta file. // This buffer should accomodate either a link path or a sfs item path. // The max limit for a link path should be more than enough for sfs item path as well. char lineBuf[SECSTOREADMIN_MAX_PATH_BYTES] = {0}; bool printedNewLine = true; while (fgets(lineBuf, sizeof(lineBuf), tmpFilePtr) != NULL) { // Remove the trailing newline char. size_t len = strlen(lineBuf); if (lineBuf[len - 1] == '\n') { lineBuf[len - 1] = '\0'; } printf("%s", lineBuf); if (printedNewLine) { printf(" "); printedNewLine = false; } else { printf("\n"); printedNewLine = true; } } // check if fgets encountered error before reaching the end of the file. if (ferror(tmpFilePtr)) { fprintf(stderr, "Error reading temp file %s. %m.\n", tmpFilePath); } /* Close the temp file. */ int r; do { r = fclose(tmpFilePtr); } while ( (r != 0) && (errno == EINTR) ); if (r != 0) { LE_EMERG("Could not close %s. %m.", tmpFilePath); /* Delete the temp file. */ if (unlink(tmpFilePath) != 0) { INTERNAL_ERR("Could not delete %s. %m.", tmpFilePath); } InternalErr(); } /* Delete the temp file. */ if (unlink(tmpFilePath) != 0) { INTERNAL_ERR("Could not delete %s. %m.", tmpFilePath); } }
//-------------------------------------------------------------------------------------------------- static void LoadSimFromConfigDb ( le_sim_Id_t simId ) { uint32_t attemptCounter = CONFIGDB_ATTEMPT_MAX; // Get the configuration path for the SIM. char configPath[LIMIT_MAX_PATH_BYTES]; snprintf(configPath, sizeof(configPath), "%s/%d", CFG_MODEMSERVICE_SIM_PATH, simId); LE_DEBUG("Start reading SIM-%d information in ConfigDB",simId); le_result_t result; le_sim_States_t simState; do { simState = le_sim_GetState(simId); switch (simState) { case LE_SIM_INSERTED: { // Check that the app has a configuration value. le_cfg_IteratorRef_t simCfg = le_cfg_CreateReadTxn(configPath); char simPin[LIMIT_MAX_PATH_BYTES] = {0}; result = le_cfg_GetString(simCfg,CFG_NODE_PIN,simPin,sizeof(simPin),""); if ( result != LE_OK ) { LE_WARN("PIN string too large for SIM-%d",simId); le_cfg_CancelTxn(simCfg); return; } if ( strncmp(simPin,"",sizeof(simPin))==0 ) { LE_WARN("PIN not set for SIM-%d",simId); le_cfg_CancelTxn(simCfg); return; } if ( (result = le_sim_EnterPIN(simId,simPin)) != LE_OK ) { LE_ERROR("Error.%d Failed to enter SIM pin for SIM-%d",result,simId); le_cfg_CancelTxn(simCfg); return; } LE_DEBUG("Sim-%d is unlocked", simId); le_cfg_CancelTxn(simCfg); attemptCounter = 1; break; } case LE_SIM_BLOCKED: { LE_EMERG("Be carefull the sim-%d is BLOCKED, need to enter PUK code",simId); attemptCounter = 1; break; } case LE_SIM_BUSY: if (attemptCounter==1) { LE_WARN("Could not load the configuration because " "the SIM is still busy after %d attempts", CONFIGDB_ATTEMPT_MAX); } else { LE_WARN("Sim-%d was busy when loading configuration," "retry in 1 seconds",simId); } sleep(1); // Retry in 1 second. break; case LE_SIM_READY: LE_DEBUG("Sim-%d is ready",simId); attemptCounter = 1; break; case LE_SIM_ABSENT: LE_WARN("Sim-%d is absent",simId); attemptCounter = 1; break; case LE_SIM_STATE_UNKNOWN: break; } } while (--attemptCounter); LE_DEBUG("Load SIM information is done"); }
//-------------------------------------------------------------------------------------------------- static inline le_result_t StartProc ( proc_Ref_t procRef, ///< [IN] The process to start. const char* workingDirPtr, ///< [IN] The path to the process's working directory, relative /// to the sandbox directory. uid_t uid, ///< [IN] The user ID to start the process as. gid_t gid, ///< [IN] The primary group ID for this process. const gid_t* groupsPtr, ///< [IN] List of supplementary groups for this process. size_t numGroups, ///< [IN] The number of groups in the supplementary groups list. const char* sandboxDirPtr ///< [IN] The path to the root of the sandbox this process is to /// run in. If NULL then process will be unsandboxed. ) { if (procRef->pid != -1) { LE_ERROR("Process '%s' (PID: %d) cannot be started because it is already running.", procRef->name, procRef->pid); return LE_FAULT; } // Create a pipe for parent/child synchronization. int syncPipeFd[2]; LE_FATAL_IF(pipe(syncPipeFd) == -1, "Could not create synchronization pipe. %m."); // @Note The current IPC system does not support forking so any reads to the config DB must be // done in the parent process. // Get the environment variables from the config tree for this process. EnvVar_t envVars[LIMIT_MAX_NUM_ENV_VARS]; int numEnvVars = GetEnvironmentVariables(procRef, envVars, LIMIT_MAX_NUM_ENV_VARS); if (numEnvVars == LE_FAULT) { LE_ERROR("Error getting environment variables. Process '%s' cannot be started.", procRef->name); return LE_FAULT; } // Get the command line arguments from the config tree for this process. char argsBuffers[LIMIT_MAX_NUM_CMD_LINE_ARGS][LIMIT_MAX_ARGS_STR_BYTES]; char* argsPtr[NUM_ARGS_PTRS]; if (GetArgs(procRef, argsBuffers, argsPtr) != LE_OK) { LE_ERROR("Could not get command line arguments, process '%s' cannot be started.", procRef->name); return LE_FAULT; } // Get the smack label for the process. // Must get the label here because smack_GetAppLabel uses the config and we can not // use any IPC after a fork. char smackLabel[LIMIT_MAX_SMACK_LABEL_BYTES]; appSmack_GetLabel(app_GetName(procRef->appRef), smackLabel, sizeof(smackLabel)); // Create pipes for the process's standard error and standard out streams. int stderrPipe[2]; int stdoutPipe[2]; CreatePipe(procRef, stderrPipe, STDERR_FILENO); CreatePipe(procRef, stdoutPipe, STDOUT_FILENO); // Create the child process pid_t pID = fork(); if (pID < 0) { LE_EMERG("Failed to fork. %m."); return LE_FAULT; } if (pID == 0) { // Wait for the parent to allow us to continue by blocking on the read pipe until it // is closed. fd_Close(syncPipeFd[WRITE_PIPE]); ssize_t numBytesRead; int dummyBuf; do { numBytesRead = read(syncPipeFd[READ_PIPE], &dummyBuf, 1); } while ( ((numBytesRead == -1) && (errno == EINTR)) || (numBytesRead != 0) ); LE_FATAL_IF(numBytesRead == -1, "Could not read synchronization pipe. %m."); // The parent has allowed us to continue. // Redirect the process's standard streams. RedirectStdStream(stderrPipe, STDERR_FILENO); RedirectStdStream(stdoutPipe, STDOUT_FILENO); // Set the process's SMACK label. smack_SetMyLabel(smackLabel); // Set the umask so that files are not accidentally created with global permissions. umask(S_IRWXG | S_IRWXO); // Unblock all signals that might have been blocked. sigset_t sigSet; LE_ASSERT(sigfillset(&sigSet) == 0); LE_ASSERT(pthread_sigmask(SIG_UNBLOCK, &sigSet, NULL) == 0); SetEnvironmentVariables(envVars, numEnvVars); // Setup the process environment. if (sandboxDirPtr != NULL) { // Sandbox the process. sandbox_ConfineProc(sandboxDirPtr, uid, gid, groupsPtr, numGroups, workingDirPtr); } else { ConfigNonSandboxedProcess(workingDirPtr); } // Launch the child program. This should not return unless there was an error. LE_INFO("Execing '%s'", argsPtr[0]); // Close all non-standard file descriptors. fd_CloseAllNonStd(); execvp(argsPtr[0], &(argsPtr[1])); // The program could not be started. Log an error message. log_ReInit(); LE_FATAL("Could not exec '%s'. %m.", argsPtr[0]); } procRef->pid = pID; procRef->paused = false; // Don't need this end of the pipe. fd_Close(syncPipeFd[READ_PIPE]); // Set the scheduling priority for the child process while the child process is blocked. SetSchedulingPriority(procRef); // Send standard pipes to the log daemon so they will show up in the logs. SendStdPipeToLogDaemon(procRef, stderrPipe, STDERR_FILENO); SendStdPipeToLogDaemon(procRef, stdoutPipe, STDOUT_FILENO); // Set the resource limits for the child process while the child process is blocked. if (resLim_SetProcLimits(procRef) != LE_OK) { LE_ERROR("Could not set the resource limits. %m."); kill_Hard(procRef->pid); } LE_INFO("Starting process %s with pid %d", procRef->name, procRef->pid); // Unblock the child process. fd_Close(syncPipeFd[WRITE_PIPE]); return LE_OK; }
//-------------------------------------------------------------------------------------------------- le_result_t fwDaemons_SigChildHandler ( pid_t pid ///< [IN] Pid of the process that produced the SIGCHLD. ) { // See which daemon produced this signal. DaemonObj_t* daemonObjPtr = NULL; int i; for (i = 0; i < NUM_ARRAY_MEMBERS(FrameworkDaemons); i++) { if (FrameworkDaemons[i].pid == pid) { daemonObjPtr = &(FrameworkDaemons[i]); // Mark this daemon as dead. daemonObjPtr->pid = -1; kill_Died(pid); break; } } if (daemonObjPtr == NULL) { return LE_NOT_FOUND; } // This child process is a framework daemon. // Reap the child now. int status = wait_ReapChild(pid); if (ShutdownIndex >= 0) { // We are in the midst of a shutdown sequence, continue the shutdown sequence. ShutdownIndex = ShutdownNextDaemon(ShutdownIndex); return LE_OK; } else { const char* daemonName = le_path_GetBasenamePtr(daemonObjPtr->path, "/"); if (WIFEXITED(status)) { // This was an unexpected error from one of the framework daemons. LE_EMERG("Framework daemon '%s' has exited with code %d.", daemonName, WEXITSTATUS(status)); } else if (WIFSIGNALED(status)) { // This was an unexpected error from one of the framework daemons. LE_EMERG("Framework daemon '%s' has been killed by a signal: %d.", daemonName, WTERMSIG(status)); } else { // This was an unexpected error from one of the framework daemons. LE_EMERG("Framework daemon '%s' has died for an unknown reason (status = 0x%x).", daemonName, status); } return LE_FAULT; } }