Merge remote-tracking branch 'origin/websrv2' into integration_2022_wk50

This commit is contained in:
Robert Schmidt
2022-12-15 16:30:33 +01:00
111 changed files with 34113 additions and 529 deletions
+21 -5
View File
@@ -19,8 +19,8 @@ in `telnetsrv.h`
*/
static int coding_setmod_cmd(char *buff, int debug, telnet_printfunc_t prnt);
static telnetshell_cmddef_t coding_cmdarray[] = {
{"mode","[sse,avx2,stdc,none]",coding_setmod_cmd},
{"","",NULL},
{"mode", "[sse,avx2,stdc,none]", coding_setmod_cmd, {NULL}, 0, NULL},
{"", "", NULL, {NULL}, 0, NULL},
};
/*
@@ -109,8 +109,24 @@ The telnet server is dynamically loaded, to use the `add_telnetcmd` function, t
| Fields | type |Description |
|:-----------|:------:|:-----------------------|
| `cmdname` | `char[TELNET_CMD_MAXSIZE]` | command name, as tested by the telnet server to check it should call the `cmdfunc` function |
| `helpstr` | `char[TELNET_HELPSTR_SIZE]` | character string to print when the elp`command is received from the telnet client |
| `cmdfunc` | `cmdfunc_t` | pointer to the function implementing the `cmdname` sub command. |
| `cmdname` | `char[TELNET_CMD_MAXSIZE]` | command name, as tested by the telnet server or web server to check it should call the `cmdfunc` or `webfunc` function |
| `helpstr` | `char[TELNET_HELPSTR_SIZE]` | character string to print when the help`command is received from the telnet client |
| `cmdfunc` | `cmdfunc_t` | pointer to the function implementing the `cmdname` telnet or web server sub command. |
| `webfunc` | `webfunc_t` or `webfunc_getdata_t` | pointer to the function implementing the `cmdname` web server sub command. |
| `cmdflags` | unsigned int bit mask | possible bits are defined in the next table |
| `qptr` | pointer to a thread pool queue | when `TELNETSRV_CMDFLAG_PUSHINTPOOLQ` bit is set in `cmdflags` , contains the queue where the command is pushed|
### `cmdflags ` bit definitions
These flags possibly modify the way the `telnetshell_cmddef_t` structure is used by the telnet server and/or the web server
| Fields | Description |
|:------------------------------------:|:-----------------------|
| TELNETSRV_CMDFLAG_PUSHINTPOOLQ | function defined in `cmdfunc` field is pushed in a thread pool queue instead of beeing executed synchronously. The queue is created by the telnet server code in the `add_telnetcmd` function|
| TELNETSRV_CMDFLAG_GETWEBTBLDATA | web server will use the `webfunc_getdata_t` version of the `webfunc` union. command results are written in a `webdatadef_t` structure instead of being printed |
| TELNETSRV_CMDFLAG_TELNETONLY | this command definition is only for the telnet server, web server is ignoring it |
| TELNETSRV_CMDFLAG_WEBSRVONLY | this command definition is only for the web server, telnet server is ignoring it |
| TELNETSRV_CMDFLAG_CONFEXEC | Currently only used by the web server, command execution has to be confirmed by user |
| TELNETSRV_CMDFLAG_NEEDPARAM | Currently only used by the web server, user must provide a parameter before command execution |
| TELNETSRV_CMDFLAG_WEBSRV_SETRETURNTBL | Currently only used by the web server, when a parameter modification requires a new page |
| TELNETSRV_CMDFLAG_AUTOUPDATE | Currently only used by the web server, the command can be rescheduled for result update |
[oai telnet server home](telnetsrv.md)
+249 -191
View File
@@ -67,51 +67,53 @@ static telnetsrv_params_t telnetparams;
#define TELNETSRV_OPTNAME_SHRMOD "shrmod"
paramdef_t telnetoptions[] = {
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* configuration parameters for telnet utility */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
{"listenaddr", "<listen ip address>\n", 0, uptr:&telnetparams.listenaddr, defstrval:"0.0.0.0", TYPE_IPV4ADDR, 0 },
{"listenport", "<local port>\n", 0, uptr:&(telnetparams.listenport), defuintval:9090, TYPE_UINT, 0 },
{"listenstdin", "enable input from stdin\n", PARAMFLAG_BOOL, uptr:&(telnetparams.listenstdin), defuintval:0, TYPE_UINT, 0 },
{"priority", "<scheduling policy (0-99)\n", 0, iptr:&telnetparams.priority, defuintval:0, TYPE_INT, 0 },
{"debug", "<debug level>\n", 0, uptr:NULL, defuintval:0, TYPE_UINT, 0 },
{"loopcount", "<loop command iterations>\n", 0, uptr:&(telnetparams.loopcount), defuintval:10, TYPE_UINT, 0 },
{"loopdelay", "<loop command delay (ms)>\n", 0, uptr:&(telnetparams.loopdelay), defuintval:5000, TYPE_UINT, 0 },
{"histfile", "<history file name>\n", PARAMFLAG_NOFREE, strptr:&(telnetparams.histfile), defstrval:"oaitelnet.history", TYPE_STRING, 0 },
{"histsize", "<history sizes>\n", 0, iptr:&(telnetparams.histsize), defuintval:50, TYPE_INT, 0 },
{"phypbsize", "<phy dump buff size (bytes)>\n",0, uptr:&(telnetparams.phyprntbuff_size),defuintval:65000, TYPE_UINT, 0 },
{TELNETSRV_OPTNAME_STATICMOD, "<static modules selection>\n", 0, strlistptr:NULL, defstrlistval:telnet_defstatmod,TYPE_STRINGLIST,(sizeof(telnet_defstatmod)/sizeof(char *))},
{TELNETSRV_OPTNAME_SHRMOD, "<dynamic modules selection>\n", 0, strlistptr:NULL, defstrlistval:NULL,TYPE_STRINGLIST,0 }
};
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
/* configuration parameters for telnet utility */
/* optname helpstr paramflags XXXptr defXXXval type numelt */
/*-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------*/
{"listenaddr", "<listen ip address>\n", 0, uptr : &telnetparams.listenaddr, defstrval : "0.0.0.0", TYPE_IPV4ADDR, 0},
{"listenport", "<local port>\n", 0, uptr : &(telnetparams.listenport), defuintval : 9090, TYPE_UINT, 0},
{"listenstdin", "enable input from stdin\n", PARAMFLAG_BOOL, uptr : &(telnetparams.listenstdin), defuintval : 0, TYPE_UINT, 0},
{"priority", "<scheduling policy (0-99)\n", 0, iptr : &telnetparams.priority, defuintval : 0, TYPE_INT, 0},
{"debug", "<debug level>\n", 0, uptr : NULL, defuintval : 0, TYPE_UINT, 0},
{"loopcount", "<loop command iterations>\n", 0, uptr : &(telnetparams.loopcount), defuintval : 10, TYPE_UINT, 0},
{"loopdelay", "<loop command delay (ms)>\n", 0, uptr : &(telnetparams.loopdelay), defuintval : 5000, TYPE_UINT, 0},
{"histfile", "<history file name>\n", PARAMFLAG_NOFREE, strptr : &(telnetparams.histfile), defstrval : "oaitelnet.history", TYPE_STRING, 0},
{"histsize", "<history sizes>\n", 0, iptr : &(telnetparams.histsize), defuintval : 50, TYPE_INT, 0},
{"logfile", "log file when redirecting", PARAMFLAG_NOFREE, strptr : &(telnetparams.logfile), defstrval : "oaisoftmodem.log", TYPE_STRING, 0},
{"phypbsize", "<phy dump buff size (bytes)>\n", 0, uptr : &(telnetparams.phyprntbuff_size), defuintval : 65000, TYPE_UINT, 0},
{TELNETSRV_OPTNAME_STATICMOD, "<static modules selection>\n", 0, strlistptr : NULL, defstrlistval : telnet_defstatmod, TYPE_STRINGLIST, (sizeof(telnet_defstatmod) / sizeof(char *))},
{TELNETSRV_OPTNAME_SHRMOD, "<dynamic modules selection>\n", 0, strlistptr : NULL, defstrlistval : NULL, TYPE_STRINGLIST, 0}};
int get_phybsize(void) {
return telnetparams.phyprntbuff_size;
};
int add_telnetcmd(char *modulename,telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd );
int setoutput(char *buff, int debug, telnet_printfunc_t prnt);
int wsetoutput(char *buff, int debug, telnet_printfunc_t prnt, ...);
int setparam(char *buff, int debug, telnet_printfunc_t prnt);
int wsetparam(char *buff, int debug, telnet_printfunc_t prnt, ...);
int history_cmd(char *buff, int debug, telnet_printfunc_t prnt);
telnetshell_vardef_t telnet_vardef[] = {
{"debug",TELNET_VARTYPE_INT32,&telnetparams.telnetdbg},
{"prio",TELNET_VARTYPE_INT32,&telnetparams.priority},
{"loopc",TELNET_VARTYPE_INT32,&telnetparams.loopcount},
{"loopd",TELNET_VARTYPE_INT32,&telnetparams.loopdelay},
{"phypb",TELNET_VARTYPE_INT32,&telnetparams.phyprntbuff_size},
{"hsize",TELNET_VARTYPE_INT32,&telnetparams.histsize},
{"hfile",TELNET_VARTYPE_STRING,&telnetparams.histfile},
{"",0,NULL}
};
telnetshell_vardef_t telnet_vardef[] = {{"debug", TELNET_VARTYPE_INT32, 0, &telnetparams.telnetdbg},
{"prio", TELNET_VARTYPE_INT32, 0, &telnetparams.priority},
{"loopc", TELNET_VARTYPE_INT32, 0, &telnetparams.loopcount},
{"loopd", TELNET_VARTYPE_INT32, 0, &telnetparams.loopdelay},
{"phypb", TELNET_VARTYPE_INT32, 0, &telnetparams.phyprntbuff_size},
{"hsize", TELNET_VARTYPE_INT32, 0, &telnetparams.histsize},
{"hfile", TELNET_VARTYPE_STRING, TELNET_CHECKVAL_RDONLY, &telnetparams.histfile},
{"logfile", TELNET_VARTYPE_STRING, 0, &telnetparams.logfile},
{"", 0, 0, NULL}};
telnetshell_cmddef_t telnet_cmdarray[] = {
{"redirlog","[here,file,off]",setoutput},
{"param","[prio]",setparam},
{"history","[list,reset]",history_cmd},
{"","",NULL},
telnetshell_cmddef_t telnet_cmdarray[] = {
{"redirlog", "[here,file,off]", setoutput, {NULL}, TELNETSRV_CMDFLAG_TELNETONLY, NULL},
{"redirlog file", "", setoutput, {NULL}, TELNETSRV_CMDFLAG_WEBSRVONLY, NULL},
{"redirlog off", "", setoutput, {NULL}, TELNETSRV_CMDFLAG_WEBSRVONLY, NULL},
{"param", "[prio]", setparam, {wsetparam}, 0, NULL},
{"history", "[list,reset]", history_cmd, {NULL}, TELNETSRV_CMDFLAG_TELNETONLY, NULL},
{"", "", NULL, {NULL}, 0, NULL},
};
void client_printf(const char *message, ...) {
va_list va_args;
va_start(va_args, message);
@@ -127,36 +129,39 @@ void client_printf(const char *message, ...) {
return ;
}
#define NICE_MAX 19
#define NICE_MIN -20
void set_sched(pthread_t tid, int pid, int priority) {
int rt;
struct sched_param schedp;
int policy;
char strpolicy[10];
int niceval = 0;
//sched_get_priority_max(SCHED_FIFO)
if (priority < NICE_MIN) {
if (priority < -100 && priority > -200) { // RR priority 1 to 99 (high) mapped to oai priority -101 to -199 (high)
policy = SCHED_RR;
sprintf(strpolicy, "%s", "RR");
schedp.sched_priority = -(priority + 100);
} else if (priority < 0 && priority > -100) {
policy=SCHED_FIFO;
sprintf(strpolicy,"%s","fifo");
schedp.sched_priority= NICE_MIN - priority ;
if ( (schedp.sched_priority < sched_get_priority_min(SCHED_FIFO)) ||
(schedp.sched_priority > sched_get_priority_max(SCHED_FIFO)) ) {
client_printf("Error: %i invalid prio, should be %i to %i, \n",
priority, NICE_MIN -sched_get_priority_min(SCHED_FIFO),
NICE_MIN - sched_get_priority_max(SCHED_FIFO) );
}
} else if (priority > NICE_MAX) {
schedp.sched_priority = -priority; // fifo priority 1 to 99 (high) mapped to oai priority -1 to -99 (high)
} else if (priority >= 0 && priority <= (NICE_MAX - NICE_MIN)) { // other (normal) nice value -20 to 19 mapped to oai priority 0 to 39
policy = SCHED_OTHER;
sprintf(strpolicy, "%s", "other");
schedp.sched_priority = 0;
niceval = priority + NICE_MIN;
} else if (priority > NICE_MAX - NICE_MIN && priority <= (2 * (NICE_MAX - NICE_MIN) + 1)) { // batch (normal) nice value -20 to 19 mapped to oai priority 40 to 79
policy = SCHED_BATCH;
sprintf(strpolicy, "%s", "batch");
niceval = priority + NICE_MIN - (NICE_MAX - NICE_MIN + 1);
schedp.sched_priority = 0;
} else if (priority > (2 * (NICE_MAX - NICE_MIN) + 1)) { // idle mapped to oai priority >79
policy=SCHED_IDLE;
sprintf(strpolicy,"%s","idle");
schedp.sched_priority=0;
} else {
policy=SCHED_OTHER;
sprintf(strpolicy,"%s","other");
schedp.sched_priority=0;
client_printf("Error: %i invalid priority \n", priority);
return;
}
if( tid != 0) {
rt = pthread_setschedparam(tid, policy, &schedp);
} else if(pid > 0) {
@@ -172,15 +177,14 @@ void set_sched(pthread_t tid, int pid, int priority) {
} else {
client_printf("policy set to %s, priority %i\n",strpolicy,schedp.sched_priority);
if ( policy==SCHED_OTHER) {
if (policy == SCHED_OTHER || policy == SCHED_BATCH) {
rt = getpriority(PRIO_PROCESS,tid);
if (rt != -1) {
rt = setpriority(PRIO_PROCESS,tid,priority);
rt = setpriority(PRIO_PROCESS, tid, niceval);
if (rt < 0) {
client_printf("Error %i: %s trying to set nice value of thread %u to %i\n",
errno,strerror(errno),tid,priority);
client_printf("Error %i: %s trying to set nice value of thread %u to %i\n", errno, strerror(errno), tid, niceval);
}
} else {
client_printf("Error %i: %s trying to get nice value of thread %u \n",
@@ -189,17 +193,17 @@ void set_sched(pthread_t tid, int pid, int priority) {
}
}
if ( policy == SCHED_OTHER) {
if (policy == SCHED_OTHER || policy == SCHED_BATCH) {
if ( tid > 0 && tid != pthread_self()) {
client_printf("setting nice value using a thread id not implemented....\n");
} else if (pid > 0) {
errno=0;
rt = setpriority(PRIO_PROCESS,pid,priority);
rt = setpriority(PRIO_PROCESS, pid, niceval);
if (rt != 0) {
client_printf("Error %i: %s calling setpriority, \n",errno,strerror(errno));
} else {
client_printf("nice value set to %i\n",priority);
client_printf("nice value set to %i\n", niceval);
}
}
}
@@ -236,20 +240,30 @@ void redirstd(char *newfname,telnet_printfunc_t prnt ) {
fd=freopen(newfname, "w", stdout);
if (fd == NULL) {
prnt("ERROR: stdout redir to %s error %s",strerror(errno));
prnt("ERROR: stdout redir to %s error %s\n", strerror(errno));
} else {
prnt("stdout redirected to %s\n", newfname);
}
fd=freopen(newfname, "w", stderr);
if (fd == NULL) {
prnt("ERROR: stderr redir to %s error %s",strerror(errno));
prnt("ERROR: stderr redir to %s error %s\n", strerror(errno));
} else {
prnt("stderr redirected to %s\n", newfname);
}
}
int wsetoutput(char *buffer, int debug, telnet_printfunc_t prnt, ...)
{
return 0;
}
int setoutput(char *buff, int debug, telnet_printfunc_t prnt) {
char cmds[TELNET_MAX_MSGLENGTH/TELNET_CMD_MAXSIZE][TELNET_CMD_MAXSIZE];
char *logfname;
char stdout_str[64];
#define LOGFILE "logfile.log"
memset(cmds,0,sizeof(cmds));
sscanf(buff,"%9s %32s %9s %9s %9s", cmds[0],cmds[1],cmds[2],cmds[3],cmds[4] );
@@ -265,10 +279,10 @@ int setoutput(char *buff, int debug, telnet_printfunc_t prnt) {
if (strncasecmp(cmds[0],"file",4) == 0) {
if (cmds[1][0] == 0)
logfname=LOGFILE;
logfname = telnetparams.logfile;
else
logfname=cmds[1];
prnt("Log output redirected to (%s)\n", logfname);
fflush(stdout);
redirstd(logfname,prnt);
}
@@ -281,6 +295,11 @@ int setoutput(char *buff, int debug, telnet_printfunc_t prnt) {
return CMDSTATUS_FOUND;
} /* setoutput */
int wsetparam(char *buff, int debug, telnet_printfunc_t prnt, ...)
{
return 0;
}
int setparam(char *buff, int debug, telnet_printfunc_t prnt) {
char cmds[TELNET_MAX_MSGLENGTH/TELNET_CMD_MAXSIZE][TELNET_CMD_MAXSIZE];
memset(cmds,0,sizeof(cmds));
@@ -344,94 +363,120 @@ int history_cmd(char *buff, int debug, telnet_printfunc_t prnt) {
/*
generic commands available for all modules loaded by the server
*/
char *telnet_getvarvalue(telnetshell_vardef_t *var, int varindex)
{
char *val;
switch (var[varindex].vartype) {
case TELNET_VARTYPE_INT32:
val = malloc(64);
snprintf(val, 64, "%i", *(int32_t *)(var[varindex].varvalptr));
break;
int setgetvar(int moduleindex,char getorset,char *params) {
int n,i;
case TELNET_VARTYPE_INT64:
val = malloc(128);
snprintf(val, 128, "%lli", (long long)*(int64_t *)(var[varindex].varvalptr));
break;
case TELNET_VARTYPE_INT16:
val = malloc(16);
snprintf(val, 16, "%hi", *(short *)(var[varindex].varvalptr));
break;
case TELNET_VARTYPE_INT8:
val = malloc(16);
snprintf(val, 16, "%i", (int)(*(int8_t *)(var[varindex].varvalptr)));
break;
case TELNET_VARTYPE_UINT:
val = malloc(64);
snprintf(val, 64, "%u", *(unsigned int *)(var[varindex].varvalptr));
break;
case TELNET_VARTYPE_DOUBLE:
val = malloc(32);
snprintf(val, 32, "%g\n", *(double *)(var[varindex].varvalptr));
break;
case TELNET_VARTYPE_STRING:
val = strdup(*(char **)(var[varindex].varvalptr));
break;
default:
val = malloc(64);
snprintf(val, 64, "ERR:var %i unknown type", varindex);
break;
}
return val;
}
int telnet_setvarvalue(telnetshell_vardef_t *var, char *strval, telnet_printfunc_t prnt)
{
int st = 0;
switch (var->vartype) {
case TELNET_VARTYPE_INT32:
*(int *)(var->varvalptr) = (int)strtol(strval, NULL, 0);
if (prnt != NULL)
prnt("%i\n", *(int *)(var->varvalptr));
break;
case TELNET_VARTYPE_INT16:
*(short *)(var->varvalptr) = (short)strtol(strval, NULL, 0);
if (prnt != NULL)
prnt("%hi\n", *(short *)(var->varvalptr));
break;
case TELNET_VARTYPE_INT8:
*(char *)(var->varvalptr) = (char)strtol(strval, NULL, 0);
if (prnt != NULL)
prnt("%i\n", *(int *)(var->varvalptr));
break;
case TELNET_VARTYPE_UINT:
*(unsigned int *)(var->varvalptr) = (unsigned int)strtol(strval, NULL, 0);
if (prnt != NULL)
prnt("%u\n", *(unsigned int *)(var->varvalptr));
break;
case TELNET_VARTYPE_DOUBLE:
*(double *)(var->varvalptr) = strtod(strval, NULL);
if (prnt != NULL)
prnt("%g\n", *(double *)(var->varvalptr));
break;
case TELNET_VARTYPE_STRING:
sprintf(*(char **)(var->varvalptr), "%s", strval);
if (prnt != NULL)
prnt("\"%s\"\n", *(char **)(var->varvalptr));
break;
default:
if (prnt != NULL)
prnt("unknown type\n");
st = -1;
break;
}
return st;
}
int setgetvar(int moduleindex, char getorset, char *params)
{
int n, i;
char varname[TELNET_CMD_MAXSIZE];
char *varval=NULL;
memset(varname,0,sizeof(varname));
n = sscanf(params,"%9s %ms",varname,&varval);
char *varval = NULL;
memset(varname, 0, sizeof(varname));
n = sscanf(params, "%9s %ms", varname, &varval);
for ( i=0 ; telnetparams.CmdParsers[moduleindex].var[i].varvalptr != NULL ; i++) {
if ( strncasecmp(telnetparams.CmdParsers[moduleindex].var[i].varname,varname,strlen(telnetparams.CmdParsers[moduleindex].var[i].varname)) == 0) {
for (i = 0; telnetparams.CmdParsers[moduleindex].var[i].varvalptr != NULL; i++) {
if (strncasecmp(telnetparams.CmdParsers[moduleindex].var[i].varname, varname, strlen(telnetparams.CmdParsers[moduleindex].var[i].varname)) == 0) {
if (n > 0 && (getorset == 'g' || getorset == 'G')) {
client_printf("%s, %s = ", telnetparams.CmdParsers[moduleindex].module,
telnetparams.CmdParsers[moduleindex].var[i].varname );
switch(telnetparams.CmdParsers[moduleindex].var[i].vartype) {
case TELNET_VARTYPE_INT32:
client_printf("%i\n",*(int32_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_INT64:
client_printf("%lli\n",*(int64_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_INT16:
client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_INT8:
client_printf("%i\n",(int)(*(int8_t *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr)));
break;
case TELNET_VARTYPE_UINT:
client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_DOUBLE:
client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_STRING:
client_printf("\"%s\"\n",*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
default:
client_printf("unknown type\n");
break;
}
client_printf("%s, %s = ", telnetparams.CmdParsers[moduleindex].module, telnetparams.CmdParsers[moduleindex].var[i].varname);
char *strval = telnet_getvarvalue(telnetparams.CmdParsers[moduleindex].var, i);
client_printf("%s\n", strval);
free(strval);
}
if (n > 1 && (getorset == 's' || getorset == 'S')) {
client_printf("%s, %s set to \n", telnetparams.CmdParsers[moduleindex].module,
telnetparams.CmdParsers[moduleindex].var[i].varname);
switch(telnetparams.CmdParsers[moduleindex].var[i].vartype) {
case TELNET_VARTYPE_INT32:
*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (int)strtol(varval,NULL,0);
client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_INT16:
*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (short)strtol(varval,NULL,0);
client_printf("%hi\n",*(short *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_INT8:
*(char *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (char)strtol(varval,NULL,0);
client_printf("%i\n",*(int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_UINT:
*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = (unsigned int)strtol(varval,NULL,0);
client_printf("%u\n",*(unsigned int *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_DOUBLE:
*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr) = strtod(varval,NULL);
client_printf("%g\n",*(double *)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
case TELNET_VARTYPE_STRING:
sprintf(*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr),"%s", varval);
client_printf("\"%s\"\n",*(char **)(telnetparams.CmdParsers[moduleindex].var[i].varvalptr));
break;
default:
client_printf("unknown type\n");
break;
}
client_printf("%s, %s set to \n", telnetparams.CmdParsers[moduleindex].module, telnetparams.CmdParsers[moduleindex].var[i].varname);
telnet_setvarvalue(&(telnetparams.CmdParsers[moduleindex].var[i]), varval, client_printf);
}
}
}
@@ -442,6 +487,14 @@ int setgetvar(int moduleindex,char getorset,char *params) {
return CMDSTATUS_VARNOTFOUND;
}
void telnetsrv_freetbldata(webdatadef_t *wdata)
{
for (int i = 0; i < wdata->numlines; i++)
for (int j = 0; j < wdata->numcols; j++)
if (wdata->columns[j].coltype & TELNET_VAR_NEEDFREE)
free(wdata->lines[i].val[j]);
}
/*----------------------------------------------------------------------------------------------------*/
char *get_time(char *buff,int bufflen) {
struct tm tmstruct;
@@ -449,17 +502,28 @@ char *get_time(char *buff,int bufflen) {
strftime (buff, bufflen, "%Y-%m-%d %H:%M:%S.000", localtime_r(&now,&tmstruct));
return buff;
}
void telnet_pushcmd(telnetshell_cmddef_t *cmd, char *cmdbuff, telnet_printfunc_t prnt)
{
notifiedFIFO_elt_t *msg = newNotifiedFIFO_elt(sizeof(telnetsrv_qmsg_t), 0, NULL, NULL);
telnetsrv_qmsg_t *cmddata = NotifiedFifoData(msg);
cmddata->cmdfunc = (qcmdfunc_t)cmd->cmdfunc;
cmddata->prnt = prnt;
cmddata->debug = telnetparams.telnetdbg;
if (cmdbuff != NULL)
cmddata->cmdbuff = strdup(cmdbuff);
pushNotifiedFIFO(cmd->qptr, msg);
}
int process_command(char *buf) {
int process_command(char *buf, int iteration)
{
int i,j,k;
char modulename[TELNET_CMD_MAXSIZE];
char cmd[TELNET_CMD_MAXSIZE];
char *cmdb=NULL;
char *bufbck;
int rt;
memset(modulename,0,sizeof(modulename));
memset(cmd,0,sizeof(cmd));
if (strncasecmp(buf,"ex",2) == 0)
return CMDSTATUS_EXIT;
@@ -474,6 +538,8 @@ int process_command(char *buf) {
}
for(j=0; telnetparams.CmdParsers[i].cmd[j].cmdfunc != NULL ; j++) {
if (telnetparams.CmdParsers[i].cmd[j].cmdflags & TELNETSRV_CMDFLAG_WEBSRVONLY)
continue;
client_printf(" %s %s %s\n",
telnetparams.CmdParsers[i].module,telnetparams.CmdParsers[i].cmd[j].cmdname,
telnetparams.CmdParsers[i].cmd[j].helpstr);
@@ -483,13 +549,11 @@ int process_command(char *buf) {
return CMDSTATUS_FOUND;
}
bufbck=strdup(buf);
rt=CMDSTATUS_NOTFOUND;
j = sscanf(buf,"%19s %19s %m[^\t\n]",modulename,cmd,&cmdb);
if (telnetparams.telnetdbg > 0)
printf("process_command: %i words, module=%s cmd=%s, parameters= %s\n",j,modulename,cmd,cmdb);
printf("process_command: %i words, module=%s cmd=%s, parameters= %s\n", j, modulename, cmd, (cmdb == NULL) ? "" : cmdb);
for (i=0; j>=2 && telnetparams.CmdParsers[i].var != NULL && telnetparams.CmdParsers[i].cmd != NULL; i++) {
if ( (strncasecmp(telnetparams.CmdParsers[i].module,modulename,strlen(telnetparams.CmdParsers[i].module)) == 0)) {
@@ -504,15 +568,11 @@ int process_command(char *buf) {
} else {
for (k=0 ; telnetparams.CmdParsers[i].cmd[k].cmdfunc != NULL ; k++) {
if (strncasecmp(cmd, telnetparams.CmdParsers[i].cmd[k].cmdname,sizeof(telnetparams.CmdParsers[i].cmd[k].cmdname)) == 0) {
if (telnetparams.CmdParsers[i].cmd[k].qptr != NULL) {
notifiedFIFO_elt_t *msg =newNotifiedFIFO_elt(sizeof(telnetsrv_qmsg_t),0,NULL,NULL);
telnetsrv_qmsg_t *cmddata=NotifiedFifoData(msg);
cmddata->cmdfunc=(qcmdfunc_t)telnetparams.CmdParsers[i].cmd[k].cmdfunc;
cmddata->prnt=client_printf;
cmddata->debug=telnetparams.telnetdbg;
cmddata->cmdbuff=cmdb ? strdup(cmdb) : NULL;
pushNotifiedFIFO(telnetparams.CmdParsers[i].cmd[k].qptr, msg);
} else {
if (telnetparams.CmdParsers[i].cmd[k].cmdflags & TELNETSRV_CMDFLAG_WEBSRVONLY)
continue;
if (telnetparams.CmdParsers[i].cmd[k].qptr != NULL) {
telnet_pushcmd(&(telnetparams.CmdParsers[i].cmd[k]), (cmdb != NULL) ? strdup(cmdb) : NULL, client_printf);
} else {
telnetparams.CmdParsers[i].cmd[k].cmdfunc(cmdb, telnetparams.telnetdbg, client_printf);
}
rt= CMDSTATUS_FOUND;
@@ -533,7 +593,7 @@ int process_command(char *buf) {
char tbuff[64];
client_printf(CSI "1J" CSI "1;10H " STDFMT "%s %i/%i\n",
get_time(tbuff,sizeof(tbuff)),lc,telnetparams.loopcount );
process_command(bufbck+strlen("loop")+1);
process_command(buf + strlen("loop") + 1, lc);
errno=0;
int rs = read(telnetparams.new_socket,dummybuff,sizeof(dummybuff));
@@ -554,7 +614,6 @@ int process_command(char *buf) {
} /* loop */
} /* for i */
free(cmdb);
free(bufbck);
return rt;
}
@@ -645,7 +704,7 @@ void run_telnetsrv(void) {
}
if (strlen(buf) > 2 ) {
status=process_command(buf);
status = process_command(buf, 0);
} else
status=CMDSTATUS_NOCMD;
@@ -847,44 +906,35 @@ int telnetsrv_autoinit(void) {
*/
int add_telnetcmd(char *modulename, telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd)
{
notifiedFIFO_t *afifo = NULL;
if( modulename == NULL || var == NULL || cmd == NULL) {
fprintf(stderr,"[TELNETSRV] Telnet server, add_telnetcmd: invalid parameters\n");
return -1;
}
int i;
for (i=0; i<TELNET_MAXCMD ; i++) {
cmdparser_t *CmdParser = &telnetparams.CmdParsers[i];
if (CmdParser->var == NULL) {
strncpy(CmdParser->module, modulename, sizeof(CmdParser->module) - 1);
CmdParser->cmd = cmd;
CmdParser->var = var;
printf("[TELNETSRV] Telnet server: module %i = %s added to shell\n",
i, CmdParser->module);
break;
}
}
if (i == TELNET_MAXCMD) {
fprintf(stderr, "[TELNETSRV] TELNET_MAXCMD reached, cannot add new module %s\n", modulename);
return -1;
}
notifiedFIFO_t *afifo = NULL;
for (int k = 0; cmd[k].cmdfunc != NULL ; k++) {
if (cmd[k].cmdflags & TELNETSRV_CMDFLAG_PUSHINTPOOLQ) {
if (afifo == NULL) {
afifo = malloc(sizeof(notifiedFIFO_t));
initNotifiedFIFO(afifo);
for (int i = 0; i < TELNET_MAXCMD; i++) {
if (telnetparams.CmdParsers[i].var == NULL) {
strncpy(telnetparams.CmdParsers[i].module, modulename, sizeof(telnetparams.CmdParsers[i].module) - 1);
telnetparams.CmdParsers[i].cmd = cmd;
telnetparams.CmdParsers[i].var = var;
for (int j = 0; cmd[j].cmdfunc != NULL; j++) {
if (cmd[j].cmdflags & TELNETSRV_CMDFLAG_PUSHINTPOOLQ) {
if (afifo == NULL) {
afifo = malloc(sizeof(notifiedFIFO_t));
initNotifiedFIFO(afifo);
}
cmd[j].qptr = afifo;
}
}
cmd[k].qptr = afifo;
printf("[TELNETSRV] Telnet server: module %i = %s added to shell\n", i, telnetparams.CmdParsers[i].module);
break;
}
}
return 0;
}
/* function which will be called by the shared lib loader, to check shared lib version
against main exec version. version mismatch not considered as fatal (interfaces not supposed to change)
*/
@@ -903,10 +953,18 @@ int telnetsrv_checkbuildver(char *mainexec_buildversion, char **shlib_buildvers
}
int telnetsrv_getfarray(loader_shlibfunc_t **farray) {
*farray=malloc(sizeof(loader_shlibfunc_t)*2);
int const num_func_tln_srv = 3;
*farray = malloc(sizeof(loader_shlibfunc_t) * num_func_tln_srv);
(*farray)[0].fname=TELNET_ADDCMD_FNAME;
(*farray)[0].fptr=(int (*)(void) )add_telnetcmd;
(*farray)[1].fname=TELNET_POLLCMDQ_FNAME;
(*farray)[1].fptr=(int (*)(void) )poll_telnetcmdq;
return ( 2);
(*farray)[1].fptr = (int (*)(void))poll_telnetcmdq;
(*farray)[2].fname = TELNET_PUSHCMD_FNAME;
(*farray)[2].fptr = (int (*)(void))telnet_pushcmd;
return (3);
}
/* for webserver interface, needs access to some telnet server paramaters */
telnetsrv_params_t *get_telnetsrv_params(void)
{
return &telnetparams;
}
+58 -2
View File
@@ -48,19 +48,54 @@
#define CMDSTATUS_VARNOTFOUND 3
#define CMDSTATUS_NOTFOUND 4
/* definitions to store 2 dim table, used to store command results before */
/* displaying them either on console or web page */
#define TELNET_MAXLINE_NUM 100
#define TELNET_MAXCOL_NUM 10
typedef struct col {
char coltitle[TELNET_CMD_MAXSIZE];
unsigned int coltype;
} acol_t;
typedef struct line {
char *val[TELNET_MAXCOL_NUM];
} aline_t;
typedef struct webdatadef {
char tblname[TELNET_HELPSTR_SIZE];
int numlines;
int numcols;
acol_t columns[TELNET_MAXCOL_NUM];
aline_t lines[TELNET_MAXLINE_NUM];
} webdatadef_t;
/*----------------------------------------------------------------------------*/
/* structure to be used when adding a module to the telnet server */
/* This is the second parameter of the add_telnetcmd function, which can be used */
/* to add a set of new command to the telnet server shell */
typedef void(*telnet_printfunc_t)(const char* format, ...);
typedef int(*cmdfunc_t)(char*, int, telnet_printfunc_t prnt);
typedef int (*webfunc_t)(char *cmdbuff, int debug, telnet_printfunc_t prnt, ...);
typedef int (*webfunc_getdata_t)(char *cmdbuff, int debug, void *data, telnet_printfunc_t prnt);
typedef int(*qcmdfunc_t)(char*, int, telnet_printfunc_t prnt,void *arg);
#define TELNETSRV_CMDFLAG_PUSHINTPOOLQ (1<<0) // ask the telnet server to push the command in a thread pool queue
#define TELNETSRV_CMDFLAG_PUSHINTPOOLQ (1 << 0) // ask the telnet server to push the command in a thread pool queue
#define TELNETSRV_CMDFLAG_GETWEBDATA (1 << 1) // When called from web server, use the getdata variant of the function
#define TELNETSRV_CMDFLAG_TELNETONLY (1 << 2) // Command only for telnet client connections
#define TELNETSRV_CMDFLAG_WEBSRVONLY (1 << 3) // Command only for web server connections
#define TELNETSRV_CMDFLAG_CONFEXEC (1 << 4) // Ask for confirm before exec
#define TELNETSRV_CMDFLAG_GETWEBTBLDATA (1 << 8) // When called from web server, use the get table data variant of the function
#define TELNETSRV_CMDFLAG_NEEDPARAM (1 << 10) // websrv: The command needs a parameter
#define TELNETSRV_CMDFLAG_WEBSRV_SETRETURNTBL (1 << 11) // websrv: set callback returns a new table
#define TELNETSRV_CMDFLAG_AUTOUPDATE (1 << 12) // command can be re-submitted automatically for result update
typedef struct cmddef {
char cmdname[TELNET_CMD_MAXSIZE];
char helpstr[TELNET_HELPSTR_SIZE];
cmdfunc_t cmdfunc;
cmdfunc_t cmdfunc;
union {
webfunc_t webfunc;
webfunc_getdata_t webfunc_getdata;
};
unsigned int cmdflags;
void *qptr;
} telnetshell_cmddef_t;
@@ -78,6 +113,8 @@ typedef struct telnetsrv_qmsg {
/*structure to be used when adding a module to the telnet server */
/* This is the first parameter of the add_telnetcmd function, which can be used */
/* to add a set of new variables which can be got/set from the telnet server shell */
/* var type: bits 0-3, type value (1 to 15)
* type modifier, bits 4-31 */
#define TELNET_VARTYPE_INT32 1
#define TELNET_VARTYPE_INT16 2
#define TELNET_VARTYPE_INT64 3
@@ -85,9 +122,16 @@ typedef struct telnetsrv_qmsg {
#define TELNET_VARTYPE_DOUBLE 5
#define TELNET_VARTYPE_INT8 6
#define TELNET_VARTYPE_UINT 7
#define TELNET_CHECKVAL_RDONLY 16
#define TELNET_CHECKVAL_BOOL 32
#define TELNET_VAR_NEEDFREE 64
#define TELNET_CHECKVAL_LOGLVL 128
#define TELNET_CHECKVAL_SIMALGO 256
typedef struct variabledef {
char varname[TELNET_CMD_MAXSIZE];
char vartype;
char checkval;
void *varvalptr;
} telnetshell_vardef_t;
@@ -113,6 +157,7 @@ typedef struct {
int priority; // server running priority
char *histfile; // command history
int histsize; // command history length
char *logfile; // filename to use when redirecting output to file
int new_socket; // socket of the client connection
int logfilefd; // file id of the log file when log output is redirected to a file
int saved_stdout; // file id of the previous stdout, used to be able to restore original stdout
@@ -145,14 +190,25 @@ VT escape sequence definition, for smarter display....
#define STDFMT "\x1b[0m"
/*---------------------------------------------------------------------------------------------*/
#define NICE_MAX 19
#define NICE_MIN -20
#define TELNET_ADDCMD_FNAME "add_telnetcmd"
#define TELNET_POLLCMDQ_FNAME "poll_telnetcmdq"
#define TELNET_PUSHCMD_FNAME "telnet_pushcmd"
typedef int(*add_telnetcmd_func_t)(char *, telnetshell_vardef_t *, telnetshell_cmddef_t *);
typedef void(*poll_telnetcmdq_func_t)(void *qid,void *arg);
typedef void (*push_telnetcmd_func_t)(telnetshell_cmddef_t *cmd, char *cmdbuff, telnet_printfunc_t prnt);
#ifdef TELNETSERVERCODE
int add_telnetcmd(char *modulename, telnetshell_vardef_t *var, telnetshell_cmddef_t *cmd);
void set_sched(pthread_t tid, int pid,int priority);
void set_affinity(pthread_t tid, int pid, int coreid);
extern int get_phybsize(void);
#endif
#ifdef WEBSERVERCODE
extern void telnet_pushcmd(telnetshell_cmddef_t *cmd, char *cmdbuff, telnet_printfunc_t prnt);
extern telnetsrv_params_t *get_telnetsrv_params(void);
extern char *telnet_getvarvalue(telnetshell_vardef_t *var, int varindex);
extern int telnet_setvarvalue(telnetshell_vardef_t *var, char *strval, telnet_printfunc_t prnt);
extern void telnetsrv_freetbldata(webdatadef_t *wdata);
#endif
#endif
@@ -32,6 +32,6 @@ endforeach()
install(TARGETS telnetsrv DESTINATION bin)
if (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build")
install(TARGETS telnetsrv DESTINATION ${OPENAIR_BUILD_DIR}/ran_build/build)
endif (EXISTS "${OPENAIR_BUILD_DIR}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_BUILD_DIR}/ran_build/build")
if (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
install(TARGETS telnetsrv DESTINATION ${OPENAIR_CMAKE}/ran_build/build)
endif (EXISTS "${OPENAIR_CMAKE}/ran_build/build" AND IS_DIRECTORY "${OPENAIR_CMAKE}/ran_build/build")
+17 -16
View File
@@ -42,14 +42,17 @@
int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt);
telnetshell_cmddef_t loader_cmdarray[] = {
{"show","[params,modules]",loader_show_cmd},
{"","",NULL},
{"show", "[params,modules]", loader_show_cmd, {(webfunc_t)loader_show_cmd}, 0, NULL},
{"", "", NULL, {NULL}, 0, NULL},
};
/*-------------------------------------------------------------------------------------*/
int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt)
{
if (buff == NULL) {
prnt("ERROR wrong loader SHOW command...\n");
return 0;
}
if (debug > 0)
prnt( "loader_show_cmd received %s\n",buff);
@@ -58,21 +61,19 @@ int loader_show_cmd(char *buff, int debug, telnet_printfunc_t prnt)
prnt( " Main executable build version: \"%s\"\n", loader_data.mainexec_buildversion);
prnt( " Default shared lib path: \"%s\"\n", loader_data.shlibpath);
prnt( " Max number of shared lib : %i\n", loader_data.maxshlibs);
}
else if (strcasestr(buff,"modules") != NULL) {
prnt( "%i shared lib have been dynamicaly loaded by the oai loader\n", loader_data.numshlibs);
for (int i=0 ; i<loader_data.numshlibs ; i++) {
prnt( " Module %i: %s\n", i,loader_data.shlibs[i].name);
prnt( " Shared library build version: \"%s\"\n",((loader_data.shlibs[i].shlib_buildversion == NULL )?"":loader_data.shlibs[i].shlib_buildversion));
prnt( " Shared library path: \"%s\"\n", loader_data.shlibs[i].thisshlib_path);
prnt( " %i function pointers registered:\n", loader_data.shlibs[i].numfunc);
for(int j=0 ; j<loader_data.shlibs[i].numfunc;j++) {
prnt( " function %i %s at %p\n",j,
loader_data.shlibs[i].funcarray[j].fname, loader_data.shlibs[i].funcarray[j].fptr);
}
} else if (strcasestr(buff, "modules") != NULL || buff[0] == 0 || strcasestr(buff, "show") != NULL) {
prnt("%i shared lib have been dynamicaly loaded by the oai loader\n", loader_data.numshlibs);
for (int i = 0; i < loader_data.numshlibs; i++) {
prnt(" Module %i: %s\n", i, loader_data.shlibs[i].name);
prnt(" Shared library build version: \"%s\"\n", ((loader_data.shlibs[i].shlib_buildversion == NULL) ? "" : loader_data.shlibs[i].shlib_buildversion));
prnt(" Shared library path: \"%s\"\n", loader_data.shlibs[i].thisshlib_path);
prnt(" %i function pointers registered:\n", loader_data.shlibs[i].numfunc);
for (int j = 0; j < loader_data.shlibs[i].numfunc; j++) {
prnt(" function %i %s at %p\n", j, loader_data.shlibs[i].funcarray[j].fname, loader_data.shlibs[i].funcarray[j].fptr);
}
}
} else {
prnt("%s: wrong loader command...\n",buff);
prnt("%s: wrong loader command...\n", buff);
}
return 0;
}
+5 -8
View File
@@ -37,14 +37,11 @@
#include "common/utils/load_module_shlib.h"
telnetshell_vardef_t loader_globalvardef[] = {
{"mainversion",TELNET_VARTYPE_STRING,&(loader_data.mainexec_buildversion)},
{"defpath",TELNET_VARTYPE_STRING,&(loader_data.shlibpath)},
{"maxshlibs",TELNET_VARTYPE_INT32,&(loader_data.maxshlibs)},
{"numshlibs",TELNET_VARTYPE_INT32,&(loader_data.numshlibs)},
{"",0,NULL}
};
telnetshell_vardef_t loader_globalvardef[] = {{"mainversion", TELNET_VARTYPE_STRING, TELNET_CHECKVAL_RDONLY, &(loader_data.mainexec_buildversion)},
{"defpath", TELNET_VARTYPE_STRING, TELNET_CHECKVAL_RDONLY, &(loader_data.shlibpath)},
{"maxshlibs", TELNET_VARTYPE_INT32, TELNET_CHECKVAL_RDONLY, &(loader_data.maxshlibs)},
{"numshlibs", TELNET_VARTYPE_INT32, TELNET_CHECKVAL_RDONLY, &(loader_data.numshlibs)},
{"", 0, 0, NULL}};
telnetshell_vardef_t *loader_modulesvardef;
extern void add_loader_cmds(void);
@@ -91,9 +91,7 @@ telnetshell_cmddef_t measur_cmdarray[] = {
{"","",NULL}
};
telnetshell_vardef_t measur_vardef[] = {
{"",0,NULL}
};
telnetshell_vardef_t measur_vardef[] = {{"", 0, 0, NULL}};
/* function to be implemented in any telnetsrv_xxx_measurements.c sources
to allow common measurment code to access measurments data */
extern int get_measurgroups(telnet_measurgroupdef_t **measurgroups);
+1 -11
View File
@@ -44,17 +44,7 @@
#define TELNETVAR_PHYCC0 0
#define TELNETVAR_PHYCC1 1
telnetshell_vardef_t phy_vardef[] = {
//{"iqmax",TELNET_VARTYPE_INT16,NULL},
//{"iqmin",TELNET_VARTYPE_INT16,NULL},
//{"loglvl",TELNET_VARTYPE_INT32,NULL},
//{"sndslp",TELNET_VARTYPE_INT32,NULL},
//{"rxrescale",TELNET_VARTYPE_INT32,NULL},
//{"txshift",TELNET_VARTYPE_INT32,NULL},
//{"rachemin",TELNET_VARTYPE_INT32,NULL},
//{"rachdmax",TELNET_VARTYPE_INT32,NULL},
{"",0,NULL}
};
telnetshell_vardef_t phy_vardef[] = {{"", 0, 0, NULL}};
#else
+313 -101
View File
@@ -57,84 +57,119 @@
#include "openair1/PHY/phy_extern.h"
#include "telnetsrv_proccmd.h"
void decode_procstat(char *record, int debug, telnet_printfunc_t prnt)
void decode_procstat(char *record, int debug, telnet_printfunc_t prnt, webdatadef_t *tdata)
{
char prntline[160];
char *procfile_fiels;
char *procfile_fields;
char *strtokptr;
char *lptr;
int fieldcnt;
char toksep[2];
fieldcnt=0;
procfile_fiels =strtok_r(record," ",&strtokptr);
lptr= prntline;
fieldcnt = 0;
procfile_fields = 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);
int priority = 0;
int nice = 0;
while (procfile_fields != NULL && fieldcnt < 42) {
long int policy;
if (strlen(procfile_fields) == 0)
continue;
fieldcnt++;
sprintf(toksep, " ");
switch (fieldcnt) {
case 1: /* id */
if (tdata != NULL) {
tdata->lines[tdata->numlines].val[0] = strdup(procfile_fields);
}
lptr += sprintf(lptr, "%9.9s ", procfile_fields);
sprintf(toksep, ")");
break;
case 2: /* name */
if (tdata != NULL) {
tdata->lines[tdata->numlines].val[1] = strdup(procfile_fields);
}
lptr += sprintf(lptr, "%20.20s ", procfile_fields + 1);
break;
case 3: // thread state
lptr += sprintf(lptr, " %c ", procfile_fields[0]);
break;
case 14: // time in user mode
case 15: // time in kernel mode
lptr += sprintf(lptr, "%9.9s ", procfile_fields);
break;
case 18: // priority column index 2 in tdata, -2 to -100 (1, min to 99, highest prio)
priority = strtol(procfile_fields, NULL, 0);
case 19: // nice column index 3 in tdata 0 to 39 (-20, highest prio, to 19)
if (tdata != NULL) {
tdata->lines[tdata->numlines].val[fieldcnt - 16] = strdup(procfile_fields);
}
lptr += sprintf(lptr, "%3.3s ", procfile_fields);
nice = strtol(procfile_fields, NULL, 0);
break;
case 23: // vsize
lptr += sprintf(lptr, "%9.9s ", procfile_fields);
break;
case 39: // processor
if (tdata != NULL) {
tdata->lines[tdata->numlines].val[4] = strdup(procfile_fields);
}
lptr += sprintf(lptr, " %2.2s ", procfile_fields);
break;
case 41: // policy
lptr += sprintf(lptr, "%3.3s ", procfile_fields);
policy = strtol(procfile_fields, NULL, 0);
char strschedp[64];
switch (policy) {
case SCHED_FIFO:
snprintf(strschedp, sizeof(strschedp), "%s ", "rt:fifo");
priority = priority + 1; // in /proc file system priority 1 to 99 mapped to -2 to -100
break;
case SCHED_OTHER:
snprintf(strschedp, sizeof(strschedp), "%s ", "other");
priority = nice - NICE_MIN; // linux nice is -20 to 19
break;
case SCHED_IDLE:
snprintf(strschedp, sizeof(strschedp), "%s ", "idle");
priority = 2 * (NICE_MAX - NICE_MIN + 1);
break;
case SCHED_BATCH:
snprintf(strschedp, sizeof(strschedp), "%s ", "batch");
priority = (NICE_MAX - NICE_MIN + 1) + nice - NICE_MIN;
break;
case SCHED_RR:
snprintf(strschedp, sizeof(strschedp), "%s ", "rt:rr");
priority = priority - 99;
break;
#ifdef SCHED_DEADLINE
case SCHED_DEADLINE:
snprintf(strschedp, sizeof(strschedp), "%s ", "rt:deadline");
break;
#endif
default:
snprintf(strschedp, sizeof(strschedp), "%s ", "????");
break;
}
lptr += sprintf(lptr, "%s ", strschedp);
if (tdata != NULL) {
tdata->lines[tdata->numlines].val[5] = strdup(strschedp);
tdata->lines[tdata->numlines].val[6] = malloc(10);
snprintf(tdata->lines[tdata->numlines].val[6], 9, "%i", priority);
}
break;
default:
break;
} /* switch on fieldcnr */
procfile_fields = strtok_r(NULL, toksep, &strtokptr);
} /* while on proc_fields != NULL */
prnt("%s\n", prntline);
if (tdata != NULL) {
tdata->numlines++;
}
} /*decode_procstat */
void read_statfile(char *fname,int debug, telnet_printfunc_t prnt)
void read_statfile(char *fname, int debug, telnet_printfunc_t prnt, webdatadef_t *tdata)
{
FILE *procfile;
char arecord[1024];
@@ -152,44 +187,207 @@ char arecord[1024];
return;
}
fclose(procfile);
decode_procstat(arecord, debug, prnt);
decode_procstat(arecord, debug, prnt, tdata);
}
void print_threads(char *buf, int debug, telnet_printfunc_t prnt)
int nullprnt(char *fmt, ...)
{
return 0;
}
void proccmd_get_threaddata(char *buf, int debug, telnet_printfunc_t fprnt, webdatadef_t *tdata)
{
char aname[256];
DIR *proc_dir;
struct dirent *entry;
DIR *proc_dir;
struct dirent *entry;
telnet_printfunc_t prnt = (fprnt != NULL) ? fprnt : (telnet_printfunc_t)nullprnt;
if (tdata != NULL) {
tdata->numcols = 7;
snprintf(tdata->columns[0].coltitle, sizeof(tdata->columns[0].coltitle), "thread id");
tdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY | TELNET_VAR_NEEDFREE;
snprintf(tdata->columns[1].coltitle, sizeof(tdata->columns[1].coltitle), "thread name");
tdata->columns[1].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY | TELNET_VAR_NEEDFREE;
snprintf(tdata->columns[2].coltitle, sizeof(tdata->columns[2].coltitle), "priority");
tdata->columns[2].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY | TELNET_VAR_NEEDFREE;
snprintf(tdata->columns[3].coltitle, sizeof(tdata->columns[3].coltitle), "nice");
tdata->columns[3].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY | TELNET_VAR_NEEDFREE;
snprintf(tdata->columns[4].coltitle, sizeof(tdata->columns[4].coltitle), "core");
tdata->columns[4].coltype = TELNET_VARTYPE_STRING | TELNET_VAR_NEEDFREE;
snprintf(tdata->columns[5].coltitle, sizeof(tdata->columns[5].coltitle), "sched policy");
tdata->columns[5].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY | TELNET_VAR_NEEDFREE;
snprintf(tdata->columns[5].coltitle, sizeof(tdata->columns[5].coltitle), "sched policy");
tdata->columns[6].coltype = TELNET_VARTYPE_STRING | TELNET_VAR_NEEDFREE;
snprintf(tdata->columns[6].coltitle, sizeof(tdata->columns[6].coltitle), "oai priority");
tdata->numlines = 0;
}
unsigned int eax = 11, ebx = 0, ecx = 1, edx = 0;
asm volatile("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "0"(eax), "2"(ecx) :);
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 */
prnt("System has %d cores %d threads %d Actual threads", eax, ebx, edx);
prnt("\n 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, NULL);
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] != '.') {
snprintf(aname, sizeof(aname), "/proc/%d/task/%.*s/stat", getpid(), (int)(sizeof(aname) - 24), entry->d_name);
read_statfile(aname, debug, prnt, tdata);
}
} /* while entry != NULL */
closedir(proc_dir);
} /* proccmd_get_threaddata */
void print_threads(char *buf, int debug, telnet_printfunc_t prnt)
{
proccmd_get_threaddata(buf, debug, prnt, NULL);
}
int proccmd_websrv_getdata(char *cmdbuff, int debug, void *data, telnet_printfunc_t prnt)
{
webdatadef_t *logsdata = (webdatadef_t *)data;
if (strncmp(cmdbuff, "set", 3) == 0) {
telnet_printfunc_t printfunc = (prnt != NULL) ? prnt : (telnet_printfunc_t)printf;
if (strcasestr(cmdbuff, "loglvl") != NULL) {
int level = map_str_to_int(log_level_names, logsdata->lines[0].val[1]);
int enabled = (strcmp(logsdata->lines[0].val[2], "true") == 0) ? 1 : 0;
int loginfile = (strcmp(logsdata->lines[0].val[3], "true") == 0) ? 1 : 0;
set_log(logsdata->numlines, level);
if (enabled == 0)
set_log(logsdata->numlines, OAILOG_DISABLE);
if (loginfile == 1) {
set_component_filelog(logsdata->numlines);
} else {
close_component_filelog(logsdata->numlines);
}
printfunc("%s log level %s is %s, output to %s\n",
logsdata->lines[0].val[0],
logsdata->lines[0].val[1],
enabled ? "enabled" : "disabled",
loginfile ? g_log->log_component[logsdata->numlines].filelog_name : "stdout");
}
if (strcasestr(cmdbuff, "logopt") != NULL) {
int optbit = map_str_to_int(log_options, logsdata->lines[0].val[0]);
if (optbit < 0) {
printfunc("option %s unknown\n", logsdata->lines[0].val[0]);
} else {
if (strcmp(logsdata->lines[0].val[1], "true") == 0) {
SET_LOG_OPTION(optbit);
} else {
CLEAR_LOG_OPTION(optbit);
}
printfunc("%s log option %s\n", logsdata->lines[0].val[0], (strcmp(logsdata->lines[0].val[1], "true") == 0) ? "enabled" : "disabled");
}
}
if (strcasestr(cmdbuff, "dbgopt") != NULL) {
int optbit = map_str_to_int(log_maskmap, logsdata->lines[0].val[0]);
if (optbit < 0) {
printfunc("debug option %s unknown\n", logsdata->lines[0].val[0]);
} else {
if (strcmp(logsdata->lines[0].val[1], "true") == 0)
SET_LOG_DEBUG(optbit);
else
CLEAR_LOG_DEBUG(optbit);
if (strcmp(logsdata->lines[0].val[2], "true") == 0)
SET_LOG_DUMP(optbit);
else
CLEAR_LOG_DUMP(optbit);
printfunc("%s debug %s dump %s\n",
logsdata->lines[0].val[0],
(strcmp(logsdata->lines[0].val[1], "true") == 0) ? "enabled" : "disabled",
(strcmp(logsdata->lines[0].val[2], "true") == 0) ? "enabled" : "disabled");
}
}
if (strcasestr(cmdbuff, "threadsched") != NULL) {
unsigned int tid = strtoll(logsdata->lines[0].val[0], NULL, 0);
unsigned int core = strtoll(logsdata->lines[0].val[4], NULL, 0);
int priority = strtoll(logsdata->lines[0].val[6], NULL, 0);
printfunc("Thread %s id %u set affinity to core %u\n", logsdata->lines[0].val[0], tid, core);
set_affinity(0, (pid_t)tid, core);
set_sched(0, (pid_t)tid, priority);
}
} else { /* end of set, => show */
if (strcasestr(cmdbuff, "loglvl") != NULL) {
logsdata->numcols = 4;
logsdata->numlines = 0;
snprintf(logsdata->columns[0].coltitle, TELNET_CMD_MAXSIZE, "component");
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
snprintf(logsdata->columns[1].coltitle, TELNET_CMD_MAXSIZE, "level");
logsdata->columns[1].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_LOGLVL;
snprintf(logsdata->columns[2].coltitle, TELNET_CMD_MAXSIZE, "enabled");
logsdata->columns[2].coltype = TELNET_CHECKVAL_BOOL;
snprintf(logsdata->columns[3].coltitle, TELNET_CMD_MAXSIZE, "in file");
logsdata->columns[3].coltype = TELNET_CHECKVAL_BOOL;
for (int i = MIN_LOG_COMPONENTS; i < MAX_LOG_COMPONENTS; i++) {
if (g_log->log_component[i].name != NULL) {
logsdata->numlines++;
logsdata->lines[i].val[0] = (char *)(g_log->log_component[i].name);
logsdata->lines[i].val[1] = 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);
logsdata->lines[i].val[2] = (g_log->log_component[i].level >= 0) ? "true" : "false";
logsdata->lines[i].val[3] = (g_log->log_component[i].filelog > 0) ? "true" : "false";
}
}
}
if (strcasestr(cmdbuff, "dbgopt") != NULL) {
webdatadef_t *logsdata = (webdatadef_t *)data;
logsdata->numcols = 3;
logsdata->numlines = 0;
snprintf(logsdata->columns[0].coltitle, TELNET_CMD_MAXSIZE, "module");
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
snprintf(logsdata->columns[1].coltitle, TELNET_CMD_MAXSIZE, "debug");
logsdata->columns[1].coltype = TELNET_CHECKVAL_BOOL;
snprintf(logsdata->columns[2].coltitle, TELNET_CMD_MAXSIZE, "dump");
logsdata->columns[2].coltype = TELNET_CHECKVAL_BOOL;
for (int i = 0; log_maskmap[i].name != NULL; i++) {
logsdata->numlines++;
logsdata->lines[i].val[0] = log_maskmap[i].name;
logsdata->lines[i].val[1] = (g_log->debug_mask & log_maskmap[i].value) ? "true" : "false";
logsdata->lines[i].val[2] = (g_log->dump_mask & log_maskmap[i].value) ? "true" : "false";
}
}
if (strcasestr(cmdbuff, "logopt") != NULL) {
webdatadef_t *logsdata = (webdatadef_t *)data;
logsdata->numcols = 2;
logsdata->numlines = 0;
snprintf(logsdata->columns[0].coltitle, TELNET_CMD_MAXSIZE, "option");
logsdata->columns[0].coltype = TELNET_VARTYPE_STRING | TELNET_CHECKVAL_RDONLY;
snprintf(logsdata->columns[1].coltitle, TELNET_CMD_MAXSIZE, "enabled");
logsdata->columns[1].coltype = TELNET_CHECKVAL_BOOL;
for (int i = 0; log_options[i].name != NULL; i++) {
logsdata->numlines++;
logsdata->lines[i].val[0] = log_options[i].name;
logsdata->lines[i].val[1] = (g_log->flag & log_options[i].value) ? "true" : "false";
}
}
if (strcasestr(cmdbuff, "threadsched") != NULL) {
proccmd_get_threaddata(cmdbuff, debug, prnt, (webdatadef_t *)data);
}
} // show
return 0;
}
int proccmd_show(char *buf, int debug, telnet_printfunc_t prnt)
{
if (buf == NULL) {
prnt("ERROR wrong softmodem SHOW command...\n");
return 0;
}
if (debug > 0)
prnt(" proccmd_show received %s\n",buf);
if (strcasestr(buf,"thread") != NULL) {
@@ -263,8 +461,12 @@ int proccmd_thread(char *buf, int debug, telnet_printfunc_t prnt)
{
int bv1,bv2;
int res;
char sv1[64];
char sv1[64];
if (buf == NULL) {
prnt("ERROR wrong thread command...\n");
return 0;
}
bv1=0;
bv2=0;
sv1[0]=0;
@@ -279,7 +481,7 @@ char sv1[64];
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);
print_threads(buf, debug, prnt);
return 0;
}
@@ -302,11 +504,20 @@ int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt)
{
if (debug > 0)
prnt("process module received %s\n",buf);
end_configmodule();
exit_fun("telnet server received exit command\n");
return 0;
}
int proccmd_restart(char *buf, int debug, telnet_printfunc_t prnt)
{
if (debug > 0)
prnt("process module received %s\n", buf);
end_configmodule();
configmodule_interface_t *cfg = config_get_if();
execvpe(cfg->argv[0], cfg->argv, environ);
return 0;
}
int proccmd_log(char *buf, int debug, telnet_printfunc_t prnt)
{
@@ -391,7 +602,7 @@ int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
SET_LOG_DUMP(optbit);
else
CLEAR_LOG_DUMP(optbit);
proccmd_show("dbgopt",debug,prnt);
proccmd_show("dump", debug, prnt);
}
}
if (logparam != NULL) free(logparam);
@@ -431,7 +642,8 @@ int s = sscanf(buf,"%ms %i-%i\n",&logsubcmd, &idx1,&idx2);
prnt("%s%s unknown log sub command \n",logparam, tmpstr);
}
} else {
prnt("%s unknown log sub command \n",logsubcmd);
level = map_str_to_int(log_level_names, tmpstr);
prnt("%s unknown log sub command \n", logsubcmd);
}
if (logparam != NULL) free(logparam);
if (tmpstr != NULL) free(tmpstr);
+25 -16
View File
@@ -44,11 +44,12 @@
extern int proccmd_show(char *buf, int debug, telnet_printfunc_t prnt);
extern int proccmd_thread(char *buf, int debug, telnet_printfunc_t prnt);
extern int proccmd_exit(char *buf, int debug, telnet_printfunc_t prnt);
extern int proccmd_restart(char *buf, int debug, telnet_printfunc_t prnt);
extern int proccmd_log(char *buf, int debug, telnet_printfunc_t prnt);
telnetshell_vardef_t proc_vardef[] = {
{"",0,NULL}
};
#define PROCCMD_LOG_HELP_STRING " log sub commands: \n\
extern int proccmd_websrv_getdata(char *cmdbuff, int debug, void *data, telnet_printfunc_t prnt);
telnetshell_vardef_t proc_vardef[] = {{"", 0, 0, NULL}};
#define PROCCMD_LOG_HELP_STRING \
" log sub commands: \n\
show: display current log configuration \n\
online, noonline: enable or disable console logs \n\
enable, disable id1-id2: enable or disable logs for components index id1 to id2 \n\
@@ -60,24 +61,32 @@ telnetshell_vardef_t proc_vardef[] = {
print_<opt> <0|1> disable or enable the \"opt\" log option, use the show command to get \
the available options\n\
dump_<mod> debug_<mod > disable or enable the debug file generation or debug code\
for \"mod\" module. use the show command to get the available modules\n"
for \"mod\" module. use the show command to get the available modules\n"
#define PROCCMD_THREAD_HELP_STRING " thread sub commands: \n\
#define PROCCMD_THREAD_HELP_STRING \
" thread sub commands: \n\
<thread id> aff <core> : set affinity of thread <thread id> to core <core> \n\
<thread id> prio <prio> : set scheduling parameters for thread <thread id> \n\
if prio < -20: linux scheduling policy set to FIFO, \n\
with priority = -20 - prio \n\
if prio > 19: linux scheduling policy set to OTHER, \n\
with priority (nice value) = prio \n\
-100 < prio < 0: linux scheduling policy set to FIFO, priority -prio, \n\
-200 < prio < -100: linux scheduling policy set to RR, priority -(prio+100), \n\
0 <= prio < 40: linux scheduling policy set to NORMAL, nice value prio-20 \n\
40 <= prio < 80: linux scheduling policy set to BATCH, nice value prio-60 \n\
prio >=80: linux scheduling policy set to IDLE \n\
use \"softmodem show thread\" to get <thread id> \n"
telnetshell_cmddef_t proc_cmdarray[] = {
{"show","loglvl|thread|config", proccmd_show},
{"log","(enter help for details)", proccmd_log},
{"thread","(enter help for details)", proccmd_thread},
{"exit","", proccmd_exit},
{"","",NULL},
{"show", "loglvl|thread|config", proccmd_show, {(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_TELNETONLY, NULL},
{"log", "(enter help for details)", proccmd_log, {NULL}, TELNETSRV_CMDFLAG_TELNETONLY, NULL},
{"show loglvl", "", proccmd_log, {(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY | TELNETSRV_CMDFLAG_GETWEBTBLDATA, NULL},
{"show logopt", "", proccmd_log, {(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY | TELNETSRV_CMDFLAG_GETWEBTBLDATA, NULL},
{"show dbgopt", "", proccmd_log, {(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY | TELNETSRV_CMDFLAG_GETWEBTBLDATA, NULL},
{"show config", "", proccmd_show, {(webfunc_t)proccmd_show}, TELNETSRV_CMDFLAG_WEBSRVONLY, NULL},
{"show thread", "", proccmd_thread, {(webfunc_t)proccmd_show}, TELNETSRV_CMDFLAG_WEBSRVONLY | TELNETSRV_CMDFLAG_AUTOUPDATE, NULL},
{"thread", "(enter help for details)", proccmd_thread, {NULL}, TELNETSRV_CMDFLAG_TELNETONLY, NULL},
{"show threadsched", "", proccmd_show, {(webfunc_t)proccmd_websrv_getdata}, TELNETSRV_CMDFLAG_WEBSRVONLY | TELNETSRV_CMDFLAG_GETWEBTBLDATA, NULL},
{"exit", "", proccmd_exit, {NULL}, TELNETSRV_CMDFLAG_CONFEXEC, NULL},
{"restart", "", proccmd_restart, {NULL}, TELNETSRV_CMDFLAG_CONFEXEC, NULL},
{"", "", NULL},
};
#else
extern void add_proccmd_cmds(void);