463 lines
15 KiB
C
463 lines
15 KiB
C
/*
|
|
* Licensed to the OpenAirInterface (OAI) Software Alliance under one or more
|
|
* contributor license agreements. See the NOTICE file distributed with
|
|
* this work for additional information regarding copyright ownership.
|
|
* The OpenAirInterface Software Alliance licenses this file to You under
|
|
* the OAI Public License, Version 1.1 (the "License"); you may not use this file
|
|
* except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.openairinterface.org/?page_id=698
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*-------------------------------------------------------------------------------
|
|
* For more information about the OpenAirInterface (OAI) Software Alliance:
|
|
* contact@openairinterface.org
|
|
*/
|
|
|
|
/*! \file common/utils/telnetsrv/telnetsrv_proccmd.c
|
|
* \brief: implementation of telnet commands related to this linux process
|
|
* \author Francois TABURET
|
|
* \date 2017
|
|
* \version 0.1
|
|
* \company NOKIA BellLabs France
|
|
* \email: francois.taburet@nokia-bell-labs.com
|
|
* \note
|
|
* \warning
|
|
*/
|
|
#define _GNU_SOURCE
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <netdb.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <fcntl.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <pthread.h>
|
|
#include <string.h>
|
|
#include <stdarg.h>
|
|
#include <dirent.h>
|
|
|
|
#define READCFG_DYNLOAD
|
|
|
|
#define TELNETSERVERCODE
|
|
#include "telnetsrv.h"
|
|
#define TELNETSRV_PROCCMD_MAIN
|
|
#include "common/utils/LOG/log.h"
|
|
#include "common/config/config_userapi.h"
|
|
#include "openair1/PHY/phy_extern.h"
|
|
#include "telnetsrv_proccmd.h"
|
|
|
|
void decode_procstat(char *record, int debug, telnet_printfunc_t prnt)
|
|
{
|
|
char prntline[160];
|
|
char *procfile_fiels;
|
|
char *strtokptr;
|
|
char *lptr;
|
|
int fieldcnt;
|
|
char toksep[2];
|
|
|
|
fieldcnt=0;
|
|
procfile_fiels =strtok_r(record," ",&strtokptr);
|
|
lptr= prntline;
|
|
/*http://man7.org/linux/man-pages/man5/proc.5.html gives the structure of the stat file */
|
|
|
|
while( procfile_fiels != NULL && fieldcnt < 42) {
|
|
long int policy;
|
|
if (strlen(procfile_fiels) == 0)
|
|
continue;
|
|
fieldcnt++;
|
|
sprintf(toksep," ");
|
|
switch(fieldcnt) {
|
|
case 1: /* id */
|
|
lptr+=sprintf(lptr,"%9.9s ",procfile_fiels);
|
|
sprintf(toksep,")");
|
|
break;
|
|
case 2: /* name */
|
|
lptr+=sprintf(lptr,"%20.20s ",procfile_fiels+1);
|
|
break;
|
|
case 3: //thread state
|
|
lptr+=sprintf(lptr," %c ",procfile_fiels[0]);
|
|
break;
|
|
case 14: //time in user mode
|
|
case 15: //time in kernel mode
|
|
lptr+=sprintf(lptr,"%9.9s ",procfile_fiels);
|
|
break;
|
|
case 18: //priority
|
|
case 19: //nice
|
|
lptr+=sprintf(lptr,"%3.3s ",procfile_fiels);
|
|
break;
|
|
case 23: //vsize
|
|
lptr+=sprintf(lptr,"%9.9s ",procfile_fiels);
|
|
break;
|
|
case 39: //processor
|
|
lptr+=sprintf(lptr," %2.2s ",procfile_fiels);
|
|
break;
|
|
case 41: //policy
|
|
lptr+=sprintf(lptr,"%3.3s ",procfile_fiels);
|
|
policy=strtol(procfile_fiels,NULL,0);
|
|
switch(policy) {
|
|
case SCHED_FIFO:
|
|
lptr+=sprintf(lptr,"%s ","rt: fifo");
|
|
break;
|
|
case SCHED_OTHER:
|
|
lptr+=sprintf(lptr,"%s ","other");
|
|
break;
|
|
case SCHED_IDLE:
|
|
lptr+=sprintf(lptr,"%s ","idle");
|
|
break;
|
|
case SCHED_BATCH:
|
|
lptr+=sprintf(lptr,"%s ","batch");
|
|
break;
|
|
case SCHED_RR:
|
|
lptr+=sprintf(lptr,"%s ","rt: rr");
|
|
break;
|
|
default:
|
|
lptr+=sprintf(lptr,"%s ","????");
|
|
break;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}/* switch on fieldcnr */
|
|
procfile_fiels =strtok_r(NULL,toksep,&strtokptr);
|
|
} /* while on proc_fields != NULL */
|
|
prnt("%s\n",prntline);
|
|
} /*decode_procstat */
|
|
|
|
void read_statfile(char *fname,int debug, telnet_printfunc_t prnt)
|
|
{
|
|
FILE *procfile;
|
|
char arecord[1024];
|
|
|
|
procfile=fopen(fname,"r");
|
|
if (procfile == NULL)
|
|
{
|
|
prnt("Error: Couldn't open %s %i %s\n",fname,errno,strerror(errno));
|
|
return;
|
|
}
|
|
if ( fgets(arecord,sizeof(arecord),procfile) == NULL)
|
|
{
|
|
prnt("Error: Nothing read from %s %i %s\n",fname,errno,strerror(errno));
|
|
fclose(procfile);
|
|
return;
|
|
}
|
|
fclose(procfile);
|
|
decode_procstat(arecord, debug, prnt);
|
|
}
|
|
|
|
void print_threads(char *buf, int debug, telnet_printfunc_t prnt)
|
|
{
|
|
char aname[256];
|
|
|
|
DIR *proc_dir;
|
|
struct dirent *entry;
|
|
|
|
|
|
|
|
prnt(" id name state USRmod KRNmod prio nice vsize proc pol \n\n");
|
|
snprintf(aname, sizeof(aname), "/proc/%d/stat", getpid());
|
|
read_statfile(aname,debug,prnt);
|
|
prnt("\n");
|
|
snprintf(aname, sizeof(aname), "/proc/%d/task", getpid());
|
|
proc_dir = opendir(aname);
|
|
if (proc_dir == NULL)
|
|
{
|
|
prnt("Error: Couldn't open %s %i %s\n",aname,errno,strerror(errno));
|
|
return;
|
|
}
|
|
|
|
while ((entry = readdir(proc_dir)) != NULL)
|
|
{
|
|
if(entry->d_name[0] == '.')
|
|
continue;
|
|
snprintf(aname, sizeof(aname), "/proc/%d/task/%.*s/stat", getpid(),(int)(sizeof(aname)-24),entry->d_name);
|
|
read_statfile(aname,debug,prnt);
|
|
} /* while entry != NULL */
|
|
closedir(proc_dir);
|
|
} /* print_threads */
|
|
|
|
|
|
int proccmd_show(char *buf, int debug, telnet_printfunc_t prnt)
|
|
{
|
|
|
|
if (debug > 0)
|
|
prnt(" proccmd_show received %s\n",buf);
|
|
if (strcasestr(buf,"thread") != NULL) {
|
|
print_threads(buf,debug,prnt);
|
|
}
|
|
if (strcasestr(buf,"loglvl") != NULL) {
|
|
prnt("\n component level enabled output\n");
|
|
for (int i=MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
|
|
if (g_log->log_component[i].name != NULL) {
|
|
prnt("%02i %17.17s:%10.10s %s %s\n",i ,g_log->log_component[i].name,
|
|
map_int_to_str(log_level_names,(g_log->log_component[i].level>=0)?g_log->log_component[i].level:g_log->log_component[i].savedlevel),
|
|
((g_log->log_component[i].level>=0)?"Y":"N"),
|
|
((g_log->log_component[i].filelog>0)?g_log->log_component[i].filelog_name:"stdout"));
|
|
}
|
|
}
|
|
}
|
|
if (strcasestr(buf,"logopt") != NULL) {
|
|
prnt("\n option enabled\n");
|
|
for (int i=0; log_options[i].name != NULL; i++) {
|
|
prnt("%02i %17.17s %10.10s \n",i ,log_options[i].name,
|
|
((g_log->flag & log_options[i].value)?"Y":"N") );
|
|
}
|
|
}
|
|
if (strcasestr(buf,"dbgopt") != NULL) {
|
|
prnt("\n module debug dumpfile\n");
|
|
for (int i=0; log_maskmap[i].name != NULL ; i++) {
|
|
prnt("%02i %17.17s %5.5s %5.5s\n",i ,log_maskmap[i].name,
|
|
((g_log->debug_mask & log_maskmap[i].value)?"Y":"N"),
|
|
((g_log->dump_mask & log_maskmap[i].value)?"Y":"N") );
|
|
}
|
|
}
|
|
if (strcasestr(buf,"config") != NULL) {
|
|
prnt("Command line arguments:\n");
|
|
for (int i=0; i < config_get_if()->argc; i++) {
|
|
prnt(" %02i %s\n",i ,config_get_if()->argv[i]);
|
|
}
|
|
prnt("Config module flags ( -O <cfg source>:<xxx>:dbgl<flags>): 0x%08x\n", config_get_if()->rtflags);
|
|
|
|
prnt(" Print config debug msg, params values (flag %u): %s\n",CONFIG_PRINTPARAMS,
|
|
((config_get_if()->rtflags & CONFIG_PRINTPARAMS) ? "Y" : "N") );
|
|
prnt(" Print config debug msg, memory management(flag %u): %s\n",CONFIG_DEBUGPTR,
|
|
((config_get_if()->rtflags & CONFIG_DEBUGPTR) ? "Y" : "N") );
|
|
prnt(" Print config debug msg, command line processing (flag %u): %s\n",CONFIG_DEBUGCMDLINE,
|
|
((config_get_if()->rtflags & CONFIG_DEBUGCMDLINE) ? "Y" : "N") );
|
|
prnt(" Don't exit if param check fails (flag %u): %s\n",CONFIG_NOABORTONCHKF,
|
|
((config_get_if()->rtflags & CONFIG_NOABORTONCHKF) ? "Y" : "N") );
|
|
prnt("Config source: %s, parameters:\n",CONFIG_GETSOURCE );
|
|
for (int i=0; i < config_get_if()->num_cfgP; i++) {
|
|
prnt(" %02i %s\n",i ,config_get_if()->cfgP[i]);
|
|
}
|
|
prnt("Softmodem components:\n");
|
|
prnt(" %02i Ru(s)\n", RC.nb_RU);
|
|
prnt(" %02i lte RRc(s), %02i NbIoT RRC(s)\n", RC.nb_inst, RC.nb_nb_iot_rrc_inst);
|
|
prnt(" %02i lte MACRLC(s), %02i NbIoT MACRLC(s)\n", RC.nb_macrlc_inst, RC.nb_nb_iot_macrlc_inst);
|
|
prnt(" %02i lte L1, %02i NbIoT L1\n", RC.nb_L1_inst, RC.nb_nb_iot_L1_inst);
|
|
|
|
for(int i=0; i<RC.nb_inst; i++) {
|
|
prnt(" lte RRC %i: %02i CC(s) \n",i,((RC.nb_CC == NULL)?0:RC.nb_CC[i]));
|
|
}
|
|
for(int i=0; i<RC.nb_L1_inst; i++) {
|
|
prnt(" lte L1 %i: %02i CC(s)\n",i,((RC.nb_L1_CC == NULL)?0:RC.nb_L1_CC[i]));
|
|
}
|
|
for(int i=0; i<RC.nb_macrlc_inst; i++) {
|
|
prnt(" lte macrlc %i: %02i CC(s)\n",i,((RC.nb_mac_CC == NULL)?0:RC.nb_mac_CC[i]));
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int proccmd_thread(char *buf, int debug, telnet_printfunc_t prnt)
|
|
{
|
|
int bv1,bv2;
|
|
int res;
|
|
char sv1[64];
|
|
|
|
bv1=0;
|
|
bv2=0;
|
|
sv1[0]=0;
|
|
if (debug > 0)
|
|
prnt("proccmd_thread received %s\n",buf);
|
|
if (strcasestr(buf,"help") != NULL) {
|
|
prnt(PROCCMD_THREAD_HELP_STRING);
|
|
return 0;
|
|
}
|
|
res=sscanf(buf,"%i %9s %i",&bv1,sv1,&bv2);
|
|
if (debug > 0)
|
|
prnt(" proccmd_thread: %i params = %i,%s,%i\n",res,bv1,sv1,bv2);
|
|
if(res != 3)
|
|
{
|
|
prnt("softmodem thread needs 3 params, %i received\n",res);
|
|
return 0;
|
|
}
|
|
|
|
|
|
if (strcasestr(sv1,"prio") != NULL)
|
|
{
|
|
set_sched(0,bv1, bv2);
|
|
}
|
|
else if (strcasestr(sv1,"aff") != NULL)
|
|
{
|
|
set_affinity(0,bv1, bv2);
|
|
}
|
|
else
|
|
{
|
|
prnt("%s is not a valid thread command\n",sv1);
|
|
}
|
|
return 0;
|
|
}
|
|
int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt)
|
|
{
|
|
if (debug > 0)
|
|
prnt("process module received %s\n",buf);
|
|
|
|
exit_fun("telnet server received exit command\n");
|
|
return 0;
|
|
}
|
|
|
|
|
|
int proccmd_log(char *buf, int debug, telnet_printfunc_t prnt)
|
|
{
|
|
int idx1=0;
|
|
int idx2=NUM_LOG_LEVEL-1;
|
|
char *logsubcmd=NULL;
|
|
|
|
int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
|
|
|
|
if (debug > 0)
|
|
prnt( "proccmd_log received %s\n s=%i sub command %s\n",buf,s,((logsubcmd==NULL)?"":logsubcmd));
|
|
|
|
if (s == 1 && logsubcmd != NULL) {
|
|
if (strcasestr(logsubcmd,"online") != NULL) {
|
|
if (strcasestr(buf,"noonline") != NULL) {
|
|
set_glog_onlinelog(0);
|
|
prnt("online logging disabled\n",buf);
|
|
} else {
|
|
set_glog_onlinelog(1);
|
|
prnt("online logging enabled\n",buf);
|
|
}
|
|
}
|
|
else if (strcasestr(logsubcmd,"show") != NULL) {
|
|
prnt("Available log levels: \n ");
|
|
for (int i=0; log_level_names[i].name != NULL; i++)
|
|
prnt("%s ",log_level_names[i].name);
|
|
prnt("\n\n");
|
|
prnt("Available display options: \n ");
|
|
for (int i=0; log_options[i].name != NULL; i++)
|
|
prnt("%s ",log_options[i].name);
|
|
prnt("\n\n");
|
|
prnt("Available debug and dump options: \n ");
|
|
for (int i=0; log_maskmap[i].name != NULL; i++)
|
|
prnt("%s ",log_maskmap[i].name);
|
|
prnt("\n\n");
|
|
proccmd_show("loglvl",debug,prnt);
|
|
proccmd_show("logopt",debug,prnt);
|
|
proccmd_show("dbgopt",debug,prnt);
|
|
}
|
|
else if (strcasestr(logsubcmd,"help") != NULL) {
|
|
prnt(PROCCMD_LOG_HELP_STRING);
|
|
} else {
|
|
prnt("%s: wrong log command...\n",logsubcmd);
|
|
}
|
|
} else if ( s == 2 && logsubcmd != NULL) {
|
|
char *opt=NULL;
|
|
char *logparam=NULL;
|
|
int l;
|
|
int optbit;
|
|
|
|
l=sscanf(logsubcmd,"%m[^'_']_%ms",&logparam,&opt);
|
|
if (l == 2 && strcmp(logparam,"print") == 0){
|
|
optbit=map_str_to_int(log_options,opt);
|
|
if (optbit < 0) {
|
|
prnt("option %s unknown\n",opt);
|
|
} else {
|
|
if (idx1 > 0)
|
|
SET_LOG_OPTION(optbit);
|
|
else
|
|
CLEAR_LOG_OPTION(optbit);
|
|
proccmd_show("logopt",debug,prnt);
|
|
}
|
|
}
|
|
else if (l == 2 && strcmp(logparam,"debug") == 0){
|
|
optbit=map_str_to_int(log_maskmap,opt);
|
|
if (optbit < 0) {
|
|
prnt("module %s unknown\n",opt);
|
|
} else {
|
|
if (idx1 > 0)
|
|
SET_LOG_DEBUG(optbit);
|
|
else
|
|
CLEAR_LOG_DEBUG(optbit);
|
|
proccmd_show("dbgopt",debug,prnt);
|
|
}
|
|
}
|
|
else if (l == 2 && strcmp(logparam,"dump") == 0){
|
|
optbit=map_str_to_int(log_maskmap,opt);
|
|
if (optbit < 0) {
|
|
prnt("module %s unknown\n",opt);
|
|
} else {
|
|
if (idx1 > 0)
|
|
SET_LOG_DUMP(optbit);
|
|
else
|
|
CLEAR_LOG_DUMP(optbit);
|
|
proccmd_show("dbgopt",debug,prnt);
|
|
}
|
|
}
|
|
if (logparam != NULL) free(logparam);
|
|
if (opt != NULL) free(opt);
|
|
} else if ( s == 3 && logsubcmd != NULL) {
|
|
int level, enable,filelog;
|
|
char *tmpstr=NULL;
|
|
char *logparam=NULL;
|
|
int l;
|
|
|
|
level = OAILOG_DISABLE - 1;
|
|
filelog = -1;
|
|
enable=-1;
|
|
l=sscanf(logsubcmd,"%m[^'_']_%m[^'_']",&logparam,&tmpstr);
|
|
if (debug > 0)
|
|
prnt("l=%i, %s %s\n",l,((logparam==NULL)?"\"\"":logparam), ((tmpstr==NULL)?"\"\"":tmpstr));
|
|
if (l ==2 ) {
|
|
if (strcmp(logparam,"level") == 0) {
|
|
level=map_str_to_int(log_level_names,tmpstr);
|
|
if (level < 0) {
|
|
prnt("level %s unknown\n",tmpstr);
|
|
level=OAILOG_DISABLE - 1;
|
|
}
|
|
} else {
|
|
prnt("%s%s unknown log sub command \n",logparam, tmpstr);
|
|
}
|
|
} else if (l ==1 ) {
|
|
if (strcmp(logparam,"enable") == 0) {
|
|
enable=1;
|
|
} else if (strcmp(logparam,"disable") == 0) {
|
|
level=OAILOG_DISABLE;
|
|
} else if (strcmp(logparam,"file") == 0) {
|
|
filelog = 1 ;
|
|
} else if (strcmp(logparam,"nofile") == 0) {
|
|
filelog = 0 ;
|
|
} else {
|
|
prnt("%s%s unknown log sub command \n",logparam, tmpstr);
|
|
}
|
|
} else {
|
|
prnt("%s unknown log sub command \n",logsubcmd);
|
|
}
|
|
if (logparam != NULL) free(logparam);
|
|
if (tmpstr != NULL) free(tmpstr);
|
|
for (int i=idx1; i<=idx2 ; i++) {
|
|
if (level >= OAILOG_DISABLE)
|
|
set_log(i, level);
|
|
else if ( enable == 1)
|
|
set_log(i,g_log->log_component[i].savedlevel);
|
|
else if ( filelog == 1 ) {
|
|
set_component_filelog(i);
|
|
} else if ( filelog == 0 ) {
|
|
close_component_filelog(i);
|
|
}
|
|
|
|
}
|
|
proccmd_show("loglvl",debug,prnt);
|
|
} else {
|
|
prnt("%s: wrong log command...\n",buf);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
/*-------------------------------------------------------------------------------------*/
|
|
|
|
void add_softmodem_cmds(void)
|
|
{
|
|
add_telnetcmd("softmodem",proc_vardef,proc_cmdarray);
|
|
}
|