Merge commit 'origin' into netspool

master
Sergey Dorofeev 13 years ago
commit b903018742

@ -1,3 +1,17 @@
=== 2011-12-25 ===
Cmdline processing code is partially rewritten.
New key -u for selection proto for IP session.
Added code to get node IP address from nodelist (INA flag).
Some maybe noisy messages in log added.
Some code rearrangements in session_call.
Added feature to try all available connection ways if not specified one
on calls from command line (IP methods then modem).
=== 2011-12-15 ===
Patch io_unix_tio.diff for OpenBSD systems running telnetted serial modem.
=== 2011-12-13 ===
Split inbound feature have added.

@ -0,0 +1 @@
To run fido under user not root, do `chmod +x /bin' and manually update group/passwd files (add uucp group and fido user)

@ -0,0 +1,11 @@
--- /home/sergey/nas/fido/src/bforce-0.22.8orig/source/bforce/io_unix_tio.c 2011-09-19 12:57:52.000000000 +0400
+++ io_unix_tio.c 2011-09-19 13:01:36.000000000 +0400
@@ -233,7 +233,7 @@
tio->c_iflag = TIO_FLOW_SOFT;
tio->c_oflag = 0;
tio->c_lflag = 0;
- tio->c_cc[VMIN] = 128;
+ tio->c_cc[VMIN] = 1;
tio->c_cc[VTIME] = 1;
#endif
}

@ -70,26 +70,39 @@ static void print_compiled_configuration(void)
static void usage(void)
{
printf_usage(NULL,
"usage: bforce [-fmh] [-I<include>] [-n<phone>] [-l<line_number>]\n"
" [-a<ip_address>] [-S<connect>] [-p<device>] <node>\n"
" bforce [-ih] [-I<include>] [-S<connect>]\n"
" <tsync|yoohoo|emsi|binkp|auto> (this implies slave mode)\n"
" bforce [-dh] [-C<config>] [-I<include>]\n"
"call:\n"
" use nodelist and config overrides\n"
" bforce [-f] [-I<include>] [-p<device>] <node>\n"
" use modem\n"
" bforce [-f] [-I<include>] -n<phone> [-l<line_number>] \n"
" [-p<device>] <node>\n"
" use TCP/IP\n"
" bforce [-I<include>] [-a<ip_address>] -u proto <node>\n"
" start on stdio\n"
" bforce [-f] [-I<include>] -o <node>\n"
"\n"
"answer:\n"
" bforce [-i] [-I<include>] [-S<connect>]\n"
" <tsync|yoohoo|emsi|binkp|auto>\n"
"\n"
"start daemon:\n"
" bforce -d [-C<config>] [-I<include>]\n"
"\n"
"stop daemon:\n"
" bforce -q [-C<config>] [-I<include>]\n"
"\n"
"options:\n"
" -d run as daemon\n"
" -q terminate daemon\n"
" -i run from inetd (for slave mode only)\n"
" -f ignore system's work time\n"
" -o starts outgoing session on stdin/stdout\n"
" -C <config> main config file name (\"%s\")\n"
" -I <config> additional config file name\n"
" -n <phone> override phone number\n"
" -l <line_number> call on this hidden line (default is 0) \n"
" -a <ip_address> override internet address\n"
" -S <connect_str> connect string (for slave mode only)\n"
" -p <port> override modem port (must be defined in config)\n"
" -h show this help message\n"
" -i run from inetd (for slave mode only)\n"
" -f ignore system's work time\n"
" -C <config> main config file name (\"%s\")\n"
" -I <config> additional config file name (one allowed)\n"
" -n <phone> override phone number\n"
" -l <line_number> call on this hidden line (default is 0) \n"
" -a <ip_address> override internet address\n"
" -S <connect_str> connect string (for slave mode only)\n"
" -p <port> override modem port (must be defined in config)\n"
" -u binkp|ifcico|telnet protocol to use over TCP/IP\n"
" -h show this help message\n"
"\n",
conf_getconfname()
);
@ -194,7 +207,7 @@ static int bforce_master(const s_bforce_opts *opts)
{
int callopt = 0;
if( opts->iaddr ) callopt |= CALLOPT_INET;
if( opts->runmode == MODE_CALL_IP ) callopt |= CALLOPT_INET;
if( opts->force ) callopt |= CALLOPT_FORCE;
rc = call_system(tmpl->addr, opts);
@ -238,99 +251,82 @@ int main(int argc, char *argv[], char *envp[])
s_bforce_opts opts;
int rc = 0;
int ch = 0;
int role = 0;
opts.runmode = MODE_UNDEFINED;
memset(&opts, '\0', sizeof(s_bforce_opts));
while( (ch=getopt(argc, argv, "hodqr:ifC:I:n:l:a:S:p:")) != EOF )
// parsing
while( (ch=getopt(argc, argv, "hfI:p:n:l:a:u:oiC:S:dq")) != EOF )
{
switch( ch ) {
case 'h':
usage();
exit(BFERR_NOERROR);
case 'd':
if( opts.inetd || opts.force || opts.phone
|| opts.hiddline || opts.iaddr || opts.connect
|| opts.device || opts.quit )
{ usage(); exit(BFERR_FATALERROR); }
else
{ opts.daemon = 1; }
break;
case 'q':
if( opts.inetd || opts.force || opts.phone
|| opts.hiddline || opts.iaddr || opts.connect
|| opts.device || opts.daemon )
{ usage(); exit(BFERR_FATALERROR); }
else
{ opts.daemon = 1; opts.quit = 1; }
break;
case 'i':
if( opts.daemon )
{ usage(); exit(BFERR_FATALERROR); }
else
{ opts.inetd = 1; }
break;
case 'f':
if( opts.daemon )
{ usage(); exit(BFERR_FATALERROR); }
else
{ opts.force = 1; }
break;
case 'o':
if( opts.dontcall )
{ usage(); exit(BFERR_FATALERROR); }
else
{ opts.dontcall = TRUE; }
break;
case 'C':
if( opts.confname ) free(opts.confname);
if( optarg ) opts.confname = (char *)xstrcpy(optarg);
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_CALL_MODEM;
if( opts.runmode != MODE_CALL_MODEM || opts.force ) { usage(); exit(BFERR_FATALERROR); }
opts.force = 1;
break;
case 'I':
if( opts.incname ) free(opts.incname);
if( optarg ) opts.incname = (char *)xstrcpy(optarg);
if( opts.incname || !optarg ) { usage(); exit(BFERR_FATALERROR); } //free(opts.incname);
opts.incname = (char *)xstrcpy(optarg);
break;
case 'p':
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_CALL_MODEM;
if( opts.runmode != MODE_CALL_MODEM || opts.device || !optarg ) { usage(); exit(BFERR_FATALERROR); }
opts.device = (char *)xstrcpy(optarg);
break;
case 'n':
if( opts.daemon )
{ usage(); exit(BFERR_FATALERROR); }
else
{
if( opts.phone ) free(opts.phone);
if( optarg ) opts.phone = (char *)xstrcpy(optarg);
}
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_CALL_MODEM;
if( opts.runmode != MODE_CALL_MODEM || opts.phone || !optarg ) { usage(); exit(BFERR_FATALERROR); }
//if( opts.phone ) free(opts.phone);
opts.phone = (char *)xstrcpy(optarg);
break;
case 'l':
if( ISDEC(optarg) && opts.daemon == 0 )
opts.hiddline = atoi(optarg);
else
{ usage(); exit(BFERR_FATALERROR); }
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_CALL_MODEM;
if( opts.runmode != MODE_CALL_MODEM || opts.hiddline || !optarg || ISDEC(optarg) ) { usage(); exit(BFERR_FATALERROR); }
opts.hiddline = atoi(optarg);
break;
case 'a':
if( opts.daemon )
{ usage(); exit(BFERR_FATALERROR); }
else
{
if( opts.iaddr ) free(opts.iaddr);
if( optarg ) opts.iaddr = (char *)xstrcpy(optarg);
}
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_CALL_IP;
if( opts.runmode != MODE_CALL_IP || opts.iphost || !optarg ) { usage(); exit(BFERR_FATALERROR); }
opts.iphost = (char *)xstrcpy(optarg);
break;
case 'u':
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_CALL_IP;
if( opts.runmode != MODE_CALL_IP || opts.ipproto || !optarg ) { usage(); exit(BFERR_FATALERROR); }
opts.ipproto = (char *)xstrcpy(optarg);
break;
case 'o':
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_CALL_STDIO;
if( opts.runmode != MODE_CALL_STDIO || opts.usestdio ) { usage(); exit(BFERR_FATALERROR); }
opts.usestdio = TRUE;
break;
case 'i':
//if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_ANSWER;
//if( opts.runmode != MODE_ANSWER || opts.inetd ) { usage(); exit(BFERR_FATALERROR); }
opts.inetd = 1;
break;
case 'C':
if( opts.confname || !optarg ) { usage(); exit(BFERR_FATALERROR); }
opts.confname = (char *)xstrcpy(optarg);
break;
case 'S':
if( opts.daemon )
{ usage(); exit(BFERR_FATALERROR); }
else
{
if( opts.connect ) free(opts.connect);
if( optarg ) opts.connect = (char *)xstrcpy(optarg);
}
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_ANSWER;
if( opts.runmode != MODE_ANSWER || opts.connect || !optarg ) { usage(); exit(BFERR_FATALERROR); }
opts.connect = (char *)xstrcpy(optarg);
break;
case 'p':
if( opts.daemon )
{ usage(); exit(BFERR_FATALERROR); }
else
{
if( opts.device ) free(opts.device);
if( optarg ) opts.device = (char *)xstrcpy(optarg);
}
case 'd':
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_DAEMON;
if( opts.runmode != MODE_DAEMON || opts.daemon || opts.quit ) { usage(); exit(BFERR_FATALERROR); }
opts.daemon = 1;
break;
case 'q':
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_DAEMON;
if( opts.runmode != MODE_DAEMON || opts.quit ) { usage(); exit(BFERR_FATALERROR); }
opts.quit = 1;
opts.daemon = 1;
break;
default :
usage();
@ -338,6 +334,12 @@ int main(int argc, char *argv[], char *envp[])
}
}
if( opts.inetd && opts.runmode != MODE_ANSWER && opts.runmode != MODE_CALL_STDIO )
{
usage();
exit(BFERR_FATALERROR);
}
/* Expression checker use it, so init first */
init_state(&state);
@ -368,37 +370,45 @@ int main(int argc, char *argv[], char *envp[])
if( strcasecmp(p, "tsync") == 0 )
{
role = 0;
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_ANSWER;
if( opts.runmode != MODE_ANSWER || opts.stype ) { usage(); exit(BFERR_FATALERROR); }
opts.stype = SESSION_FTSC;
}
else if( strcasecmp(p, "yoohoo") == 0 )
{
role = 0;
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_ANSWER;
if( opts.runmode != MODE_ANSWER || opts.stype ) { usage(); exit(BFERR_FATALERROR); }
opts.stype = SESSION_YOOHOO;
}
else if( strcasecmp(p, "**EMSI_INQC816") == 0 )
{
role = 0;
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_ANSWER;
if( opts.runmode != MODE_ANSWER || opts.stype ) { usage(); exit(BFERR_FATALERROR); }
opts.stype = SESSION_EMSI;
}
else if( strncasecmp(p, "emsi", 4) == 0 )
{
role = 0;
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_ANSWER;
if( opts.runmode != MODE_ANSWER || opts.stype ) { usage(); exit(BFERR_FATALERROR); }
opts.stype = SESSION_EMSI;
}
else if( strcasecmp(p, "binkp") == 0 )
{
role = 0;
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_ANSWER;
if( opts.runmode != MODE_ANSWER || opts.stype ) { usage(); exit(BFERR_FATALERROR); }
opts.stype = SESSION_BINKP;
}
else if( strcasecmp(p, "auto") == 0 )
{
role = 0;
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_ANSWER;
if( opts.runmode != MODE_ANSWER || opts.stype ) { usage(); exit(BFERR_FATALERROR); }
opts.stype = SESSION_UNKNOWN;
}
else if( ftn_addrparse(&addr, p, FALSE) == 0 )
{
role = 1;
if( opts.runmode == MODE_UNDEFINED ) opts.runmode = MODE_CALL_DEFAULT;
if( opts.runmode != MODE_CALL_DEFAULT && opts.runmode != MODE_CALL_IP &&
opts.runmode != MODE_CALL_MODEM && opts.runmode != MODE_CALL_STDIO ) { usage(); exit(BFERR_FATALERROR); }
(*alist) = (s_falist*)xmalloc(sizeof(s_falist));
memset(*alist, '\0', sizeof(s_falist));
(*alist)->addr = addr;
@ -411,12 +421,6 @@ int main(int argc, char *argv[], char *envp[])
exit(BFERR_FATALERROR);
}
}
if( opts.dontcall && role == 0 )
{
usage();
exit(BFERR_FATALERROR);
}
}
/* if( (rc = log_open(log_getfilename(LOG_FILE_SESSION), NULL, NULL)) )
@ -449,12 +453,30 @@ int main(int argc, char *argv[], char *envp[])
(void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG));
#endif
if( opts.daemon )
//char runmode_str[21];
//snprintf(runmode_str, 20, "Run mode: %d", opts.runmode);
//log(runmode_str);
switch( opts.runmode )
{
case MODE_DAEMON:
log("Daemon mode");
rc = bforce_daemon(&opts);
else if( role )
break;
case MODE_CALL_DEFAULT:
case MODE_CALL_IP:
case MODE_CALL_MODEM:
case MODE_CALL_STDIO:
log("Outgoing call");
rc = bforce_master(&opts);
else
break;
case MODE_ANSWER:
log("Start answer");
rc = bforce_slave(&opts);
break;
default:
log("Could not determine run mode");
}
exit:
@ -475,7 +497,8 @@ static void deinit_opts(s_bforce_opts *opts)
if( opts->confname ) free(opts->confname);
if( opts->incname ) free(opts->incname);
if( opts->phone ) free(opts->phone);
if( opts->iaddr ) free(opts->iaddr);
if( opts->iphost ) free(opts->iphost);
if( opts->ipproto ) free(opts->ipproto);
if( opts->connect ) free(opts->connect);
if( opts->device ) free(opts->device);
if( opts->addrlist ) deinit_falist(opts->addrlist);

@ -174,8 +174,8 @@ s_conf_entry bforce_config[BFORCE_NUMBER_OF_KEYWORDS+1] = {
#ifdef DEBUG
CONF_KEY(debug_file, CT_STRING),
CONF_KEY(debug_level, CT_DEBLEVEL),
CONF_KEY(split_inbound, CT_BOOLEAN),
#endif
CONF_KEY(split_inbound, CT_BOOLEAN),
CONF_END()
};

@ -52,78 +52,19 @@ static int daemon_call_branch(s_sysentry *syst, const char *lockdir, s_modemport
signal(SIGUSR1, SIG_DFL);
signal(SIGUSR2, SIG_DFL);
/*
* Initialise ``state'' information structure
*/
init_state(&state);
state.caller = TRUE;
state.valid = TRUE;
state.node = syst->node;
state.listed = syst->node.listed;
state.modemport = (!syst->tcpip) ? port : NULL;
if( syst->lineptr )
state.override = *syst->lineptr;
if( *state.node.addr.domain )
*state.node.addr.domain = '\0';
/*
* Apply overrides to the node information
*/
if( state.override.sFlags )
{
strnxcat(state.node.flags, ",", sizeof(state.node.flags));
strnxcat(state.node.flags, state.override.sFlags, sizeof(state.node.flags));
}
if( !syst->tcpip && state.override.sPhone )
(void)strnxcpy(state.node.phone, state.override.sPhone, sizeof(state.node.phone));
else if( syst->tcpip && state.override.sIpaddr )
(void)strnxcpy(state.node.phone, state.override.sIpaddr, sizeof(state.node.phone));
/*
* Try to lock address of system we are going to call
*/
#ifdef BFORCE_USE_CSY
if( out_bsy_lock(state.node.addr, TRUE) )
#else
if( out_bsy_lock(state.node.addr) )
#endif
gotoexit(BFERR_SYSTEM_LOCKED);
setproctitle("bforce calling %s, %s",
ftn_addrstr(abuf, state.node.addr), state.node.phone);
/* if( ( syst->tcpip ) || (strcmp(state.node.phone,NO_PSTN_PHONE)== 0) ) */
if( syst->tcpip )
{
rc = call_system_tcpip();
}
else /* via Modem */
{
state.modemport = port;
if( port_lock(lockdir, state.modemport) )
{
log("cannot lock modem port");
rc = BFERR_PORTBUSY;
}
else /* Locked port */
{
rc = call_system_modem();
port_unlock(lockdir, state.modemport);
}
}
exit:
out_bsy_unlockall();
log("session rc = %d (\"%s\")", rc, BFERR_NAME(rc));
(void)session_stat_update(&state.node.addr,
&state.sess_stat, TRUE, rc);
deinit_state(&state);
return rc;
s_bforce_opts opts;
// TODO: add hiddenline round-robin
opts.hiddline=0;
opts.runmode = MODE_CALL_DEFAULT;
opts.ipproto = NULL;
opts.phone = NULL;
opts.force = 0;
opts.inetd = 0;
opts.connect = NULL;
opts.device = NULL;
// log("doing call_system");
return call_system(syst->node.addr, &opts);
}
int daemon_call(s_sysentry *syst)

@ -59,6 +59,9 @@ bool modem_isgood_phone(const char *str)
if( string_casestr(str, "none") )
return FALSE;
if( string_casestr(str, "00-00-000000") )
return FALSE;
return TRUE;
}

@ -11,6 +11,9 @@
* $Id$
*/
#define _GNU_SOURCE
#include <string.h>
#include "includes.h"
#include "confread.h"
#include "logger.h"
@ -49,20 +52,73 @@ struct keyword {
*/
int nodelist_checkflag(const char *nodeflags, const char *flag)
{
char *p, *q;
char *p;
const char *searchbase = nodeflags;
char *q;
if( (p = strstr(nodeflags, flag)) )
while( p = strstr(searchbase, flag) )
{
if( p == nodeflags || *(p-1) == ',' )
if( p == searchbase || *(p-1) == ',' )
{
if( (q = strchr(p, ',')) == NULL || (q - p) == strlen(flag) )
return 0;
if( (strchrnul(p, ':') - p) == strlen(flag) )
return 0;
}
searchbase = p + 1; // avoid finding again the same
}
return 1;
}
/*****************************************************************************
* Get value from flag (e.g. INA:host.domain.ru)
*
* Arguments:
* nodeflags pointer to the node's nodelist flags string
* flag pointer to the flag that we want to check
* value pointer to string buffer for result. please allocate
* max possible value of strlen(nodeflags) bytes
*
* Return value:
* zero value if flag is presented in flags, and non-zero if not
* res is zero lengh string if no flag or flag is empty
*/
int nodelist_flagvalue(const char *nodeflags, const char *flag, char *res)
{
char *p, *q;
const char *searchbase = nodeflags;
int flaglen = strlen(flag);
while( p = strstr(searchbase, flag) )
{
if( p == nodeflags || *(p-1) == ',' ) // match flag
{
if( *(p+flaglen) == 0 || *(p+flaglen) == ',' )
{
// empty flag
res[0]=0;
return 0;
}
else
{
if( *(p+flaglen) == ':' ) {
// flag has data
p += flaglen + 1; // start of data
q = strchrnul(p, ','); // end of data: comma or EOS
strncpy(res, p, q-p);
return 0;
}
}
}
searchbase = p + 1;
}
res[0] = 0;
return 1;
}
/*****************************************************************************
* Get nodelist keyword (e.g. Host, Hub, Point, etc.) value
* (e.g. KEYWORD_HOST, KEYWORD_HUB, etc.)
@ -231,6 +287,12 @@ int nodelist_parsestring(s_node *node, char *str)
}
}
node->do_binkp = nodelist_checkflag(node->flags, "IBN") == 0;
node->do_ifcico = nodelist_checkflag(node->flags, "IFC") == 0;
node->do_telnet = nodelist_checkflag(node->flags, "ITN") == 0;
nodelist_flagvalue(node->flags, "INA", node->host);
return 0;
}

@ -425,7 +425,9 @@ int binkp_transfer(s_protinfo *pi) {
BPT_EOB
} binkp_send_state = BPT_Start_Send_File;
remote = (s_binkp_sysinfo *) state.handshake->remote_data;
binkp_init_bpinfo(&bpi);
while (1) {
if (binkp_send_state == BPT_Start_Send_File) {
if (p_tx_fopen (pi)) {
@ -699,10 +701,12 @@ int binkp_transfer(s_protinfo *pi) {
}
} /* end of while( !sent_EOB || !rcvd_EOB ) */
FinishSession:
if( binkp_flush_queue(&bpi, bpi.timeout) && rc == PRC_NOERROR )
rc = PRC_ERROR;
exit:
if( pi->send && pi->send->fp ) p_tx_fclose(pi);
if( pi->recv && pi->recv->fp ) p_rx_fclose(pi);

@ -1454,10 +1454,12 @@ void init_protinfo(s_protinfo *pi, bool caller)
long tmp;
long sesslimit;
memset(pi, '\0', sizeof(s_protinfo));
pi->start_time = time(NULL);
if( (pi->buflen = conf_number(cf_recv_buffer_size)) > 0 )
pi->buflen = (pi->buflen / 2048) * 2048;
else
@ -1471,6 +1473,7 @@ void init_protinfo(s_protinfo *pi, bool caller)
else
pi->min_cps_time = 60;
/*
* Set abort time if session limit was specified
*/

@ -81,8 +81,14 @@ int answ_system(e_session type, char *connstr, int inetd)
logerr("can't get client address");
else
{
#ifdef IPV6
>char addr_str[INET6_ADDRSTRLEN+1];
state.peername = (char*)xstrcpy(inet_ntop(AF_INET6, client.sin6_addr, addr_str, INET6_ADDRSTRLEN));
state.peerport = (long)ntohs(client.sin6_port);
#else
state.peername = (char*)xstrcpy(inet_ntoa(client.sin_addr));
state.peerport = (long)ntohs(client.sin_port);
#endif
}
}

@ -19,6 +19,13 @@
#include "io.h"
#include "session.h"
#define CALL_STDIO (1)
#define CALL_MODEM (2)
#define CALL_TCPIP_BINKP (4)
#define CALL_TCPIP_IFCICO (8)
#define CALL_TCPIP_TELNET (16)
#define CALL_TCPIP_ANY (CALL_TCPIP_BINKP | CALL_TCPIP_IFCICO | CALL_TCPIP_TELNET)
#ifdef XXXX
/* Unused */
int call_system_modem_init(TIO *old_tio_settings)
@ -254,8 +261,14 @@ int call_system_quiet(const char *connstr, bool inet)
logerr("can't get client address");
else
{
#ifdef IPV6
char addr_str[INET6_ADDRSTRLEN+1];
state.peername = (char*)xstrcpy(inet_ntop(AF_INET6, client.sin6_addr, addr_str, INET6_ADDRSTRLEN));
state.peerport = (long)ntohs(client.sin6_port);
#else
state.peername = (char*)xstrcpy(inet_ntoa(client.sin_addr));
state.peerport = (long)ntohs(client.sin_port);
#endif
}
}
@ -320,6 +333,9 @@ int call_system_modem(void)
const char *p_hangstr = NULL; /* Modem hangup string */
const char *p_statstr = NULL; /* Modem statistic string */
// automatically determine session type
state.session = SESSION_UNKNOWN;
/*
* Set verbal line name to the modem device name
*/
@ -468,7 +484,7 @@ int call_system_modem(void)
return rc;
}
int call_system_tcpip(void)
int call_system_tcpip(int callwith) // only TCPIP values
{
char abuf[BF_MAXADDRSTR+1];
int rc = BFERR_NOERROR;
@ -476,8 +492,8 @@ int call_system_tcpip(void)
/*
* Set verbal line name to "tcpip" value
*/
state.linename = xstrcpy("tcpip");
state.linename = xstrcpy("tcpip");
state.inet = TRUE;
/*
@ -494,34 +510,30 @@ int call_system_tcpip(void)
(void)debug_setfilename(log_getfilename(LOG_FILE_DEBUG));
#endif
if( nodelist_checkflag(state.node.flags, "BINKP") == 0
|| nodelist_checkflag(state.node.flags, "IBN") == 0 )
{
switch( callwith ) {
case CALL_TCPIP_BINKP:
state.tcpmode = TCPMODE_BINKP;
state.session = SESSION_BINKP;
}
else if( nodelist_checkflag(state.node.flags, "TELN") == 0 )
{
state.tcpmode = TCPMODE_TELNET;
state.session = SESSION_UNKNOWN;
}
else if( nodelist_checkflag(state.node.flags, "IFC") == 0 )
{
break;
case CALL_TCPIP_IFCICO:
state.tcpmode = TCPMODE_RAW;
state.session = SESSION_UNKNOWN;
}
else /* Default is "raw" mode */
{
state.tcpmode = TCPMODE_RAW;
break;
case CALL_TCPIP_TELNET:
state.tcpmode = TCPMODE_TELNET;
state.session = SESSION_UNKNOWN;
break;
defalt:
log("invalid protocol for TCP/IP module");
return BFERR_FATALERROR;
}
log("calling %s (%s, %s)",
ftn_addrstr(abuf, state.node.addr),
(state.node.name && *state.node.name ) ? state.node.name : "<none>",
(state.node.phone && *state.node.phone) ? state.node.phone : "<none>");
(state.node.host && *state.node.host) ? state.node.host : "<none>");
if( (rc = tcpip_connect(state.node.phone, state.tcpmode)) == 0
if( (rc = tcpip_connect(state.node.host, state.tcpmode)) == 0
&& (rc = tcpip_init() == 0) )
{
TTYSTATUS(1);
@ -538,117 +550,229 @@ int call_system_tcpip(void)
int call_system(s_faddr addr, const s_bforce_opts *opts)
{
// if added new opts check daemon_call
char s[300];
snprintf(s, 299, "bforce calling system %d:%d/%d.%d", addr.zone, addr.net, addr.node, addr.point );
log(s);
// find suitable way of connection and try to make session
int rc = 0;
int runrc = 0;
char abuf[BF_MAXADDRSTR+1];
char *p_lockdir = NULL;
char *errmsg = NULL;
bool inet = FALSE;
int call_mustuse = 0;
int call_mayuse = 0;
init_state(&state);
state.caller = TRUE;
state.valid = TRUE;
state.node.addr = addr;
nodelist_lookup(&state.node, addr);
state.listed = state.node.listed;
state.node.addr.domain[0] = '\0'; /* Discard domain for node address */
if( opts->dontcall )
goto do_session;
/*
* Get node overrides
*/
nodelist_lookup(&state.node, addr);
if( override_get(&state.override, state.node.addr, opts->hiddline) )
{
errmsg = "incorrect hidden line number";
gotoexit(BFERR_PHONE_UNKNOWN);
}
/*
* Apply overrides to the node information
*/
if( state.override.sFlags )
{
strnxcat(state.node.flags, ",", sizeof(state.node.flags));
strnxcat(state.node.flags, state.override.sFlags, sizeof(state.node.flags));
}
state.listed = state.node.listed;
state.node.addr.domain[0] = '\0'; /* Discard domain for node address */
if( opts->iaddr && *opts->iaddr )
{
inet = TRUE;
(void)strnxcpy(state.node.phone,
opts->iaddr, sizeof(state.node.phone));
}
else if( opts->phone && *opts->phone )
// 1. If call method specified in cmdline, do use it
// 2. If not, use nodelist data and overrides and call all available methods
// If override contains Phone or IP flags, ignore nodelist connect methods (but save INA if not overrided)
// 1st - get all allowed call ways
// 2nd - gather information reqired to call and remove unavailable ways (no info, node does not support)
call_mayuse = 0;
if( opts->runmode == MODE_CALL_DEFAULT )
{
(void)strnxcpy(state.node.phone,
opts->phone, sizeof(state.node.phone));
call_mayuse = CALL_MODEM | CALL_TCPIP_ANY;
}
else if( state.override.sIpaddr )
else if( opts->runmode == MODE_CALL_STDIO )
{
inet = TRUE;
(void)strnxcpy(state.node.phone,
state.override.sIpaddr, sizeof(state.node.phone));
call_mustuse = CALL_STDIO;
}
else if( state.override.sPhone )
else if( opts->runmode == MODE_CALL_MODEM )
{
(void)strnxcpy(state.node.phone,
state.override.sPhone, sizeof(state.node.phone));
call_mustuse = CALL_MODEM;
}
if( !inet )
else if( opts->runmode == MODE_CALL_IP )
{
if( !modem_isgood_phone(state.node.phone) )
errmsg = "don't know phone number";
if( strcasecmp(opts->ipproto, "binkp") == 0 )
{
call_mustuse = CALL_TCPIP_BINKP;
}
else if ( strcasecmp(opts->ipproto, "ifcico") == 0 )
{
call_mustuse = CALL_TCPIP_IFCICO;
}
else if( strcasecmp(opts->ipproto, "telnet") == 0 )
{
call_mustuse = CALL_TCPIP_TELNET;
}
else if( opts->ipproto == NULL ) // determine from nodelist/override
{
call_mayuse = CALL_TCPIP_ANY;
call_mustuse = 0;
}
else
{
log("Unknown protocol");
return -1;
}
}
else
{
if( !tcpip_isgood_host(state.node.phone) )
errmsg = "don't know host name";
log("Unknown protocol");
return -1;
}
if( errmsg )
gotoexit(BFERR_PHONE_UNKNOWN);
call_mayuse |= call_mustuse; // it simplifies logics: all required is allowed
//char s[300];
//snprintf(s, 299, "initial: may use %d must use %d", call_mayuse, call_mustuse);
//log(s);
if( call_mayuse & CALL_MODEM )
{
// 1. use phone from opts
// 2. use overrides
// 3. use nodelist
if( opts->phone && *opts->phone )
{
(void)strnxcpy(state.node.phone, opts->phone, sizeof(state.node.phone));
//log("phone from options");
}
else if( state.override.sPhone )
{
(void)strnxcpy(state.node.phone, state.override.sPhone, sizeof(state.node.phone));
//log("phone from override");
}
if( !modem_isgood_phone(state.node.phone) )
{
log("bad phone, excluding modem");
call_mayuse &= ~CALL_MODEM;
if( call_mustuse & CALL_MODEM )
{
errmsg = "don't know phone number";
gotoexit(BFERR_PHONE_UNKNOWN);
}
} else
if( !opts->force)
{
/*
* Is now a working time for that node/line
*/
if( !inet && !opts->force)
{
time_t unixtime = time(NULL);
struct tm *now = localtime(&unixtime);
bool goodtime;
time_t unixtime = time(NULL);
struct tm *now = localtime(&unixtime);
bool goodtime = FALSE;
if( !opts->hiddline )
{
if( state.override.sFlags && !nodelist_checkflag(state.override.sFlags, "CM") )
goodtime = TRUE;
else
if( timevec_isdefined(&state.override.worktime) )
{
goodtime = timevec_isnow(&state.override.worktime, now);
}
else if( state.override.sFlags )
{
if( timevec_isdefined(&state.override.worktime) )
goodtime = timevec_isnow(&state.override.worktime, now);
goodtime = !nodelist_checkflag(state.override.sFlags, "CM");
}
else if( !opts->hiddline )
{
if( !nodelist_checkflag(state.node.flags, "CM") )
goodtime = TRUE;
else
goodtime = timevec_isnow(&state.node.worktime, now);
}
if( !goodtime )
{
call_mayuse &= ~CALL_MODEM;
log("bad worktime, excluding modem");
if( call_mustuse & CALL_MODEM )
{
if( !nodelist_checkflag(state.node.flags, "CM") )
goodtime = TRUE;
else
goodtime = timevec_isnow(&state.node.worktime, now);
errmsg = "not works now, try later";
gotoexit(BFERR_NOTWORKING);
}
}
}
else
goodtime = timevec_isnow(&state.override.worktime, now);
}
// snprintf(s, 299, "after phone check: may use %d must use %d", call_mayuse, call_mustuse);
// log(s);
/*
* Apply overrides to the node information
*/
if( state.override.sFlags )
{
strnxcat(state.node.flags, ",", sizeof(state.node.flags));
strnxcat(state.node.flags, state.override.sFlags, sizeof(state.node.flags));
}
// state.node nodelist
// state.override config
// opts cmdline
if( !goodtime )
// filter unavailable protos if not obligated to use it
if( !(call_mustuse & CALL_TCPIP_BINKP) && (call_mayuse & CALL_TCPIP_BINKP) )
{
if( nodelist_checkflag(state.node.flags, "BINKP") != 0 && nodelist_checkflag(state.node.flags, "IBN") != 0 )
{
errmsg = "not works now, try later";
gotoexit(BFERR_NOTWORKING);
call_mayuse &= ~CALL_TCPIP_BINKP;
}
}
do_session:
if( !(call_mustuse & CALL_TCPIP_IFCICO) && (call_mayuse & CALL_TCPIP_IFCICO) )
{
if( nodelist_checkflag(state.node.flags, "IFC") != 0 && nodelist_checkflag(state.node.flags, "IFC") != 0 )
{
call_mayuse &= ~CALL_TCPIP_IFCICO;
}
}
if( !(call_mustuse & CALL_TCPIP_TELNET) && (call_mayuse & CALL_TCPIP_TELNET) )
{
if( nodelist_checkflag(state.node.flags, "TELN") != 0 && nodelist_checkflag(state.node.flags, "TLN") != 0 )
{
call_mayuse &= ~CALL_TCPIP_TELNET;
}
}
if( opts->iphost && *opts->iphost )
{
(void)strnxcpy(state.node.host, opts->iphost, sizeof(state.node.host));
}
else if( state.override.sIpaddr )
{
(void)strnxcpy(state.node.host,
state.override.sIpaddr, sizeof(state.node.host));
}
if( call_mayuse & CALL_TCPIP_ANY && !tcpip_isgood_host(state.node.host) )
{
call_mayuse &= ~CALL_TCPIP_ANY;
log("bad host, exclude IP");
if( call_mustuse & CALL_TCPIP_ANY )
{
errmsg = "don't know host name";
gotoexit(BFERR_PHONE_UNKNOWN);
}
}
// snprintf(s, 299, "after IP check: may use %d must use %d", call_mayuse, call_mustuse);
// log(s);
//do_session:
/*
* It's easier to ignore than handle! After connect
* new handlers must be installed, don't worry.
@ -677,48 +801,69 @@ do_session:
}
}
setproctitle("bforce calling %.32s, %.32s",
ftn_addrstr(abuf, state.node.addr), state.node.phone);
if( opts->dontcall )
// try allowed methods and break if rc == 0
rc = -1;
if( rc && call_mayuse & CALL_STDIO )
{
rc = call_system_quiet(opts->connect, opts->inetd);
}
else if( !inet )
if( rc && call_mayuse & CALL_TCPIP_BINKP )
{
rc = call_system_tcpip(CALL_TCPIP_BINKP);
}
if( rc && call_mayuse & CALL_TCPIP_IFCICO )
{
rc = call_system_tcpip(CALL_TCPIP_IFCICO);
}
if( rc && call_mayuse & CALL_TCPIP_TELNET )
{
rc = call_system_tcpip(CALL_TCPIP_TELNET);
}
if( rc && call_mayuse & CALL_MODEM )
{
setproctitle("bforce calling %.32s, %.32s",
ftn_addrstr(abuf, state.node.addr), state.node.phone);
rc = -1;
if( (p_lockdir = conf_string(cf_uucp_lock_directory)) == NULL )
p_lockdir = BFORCE_LOCK_DIR;
if( opts->device && *opts->device )
{
if( (state.modemport =
modem_getmatch_port(opts->device)) == NULL )
{
errmsg = "unknown port name";
gotoexit(BFERR_PORTBUSY);
}
state.modemport = modem_getmatch_port(opts->device);
}
else if( (state.modemport =
modem_getfree_port(p_lockdir)) == NULL )
else
{
errmsg = "no free matching ports";
gotoexit(BFERR_PORTBUSY);
state.modemport = modem_getfree_port(p_lockdir);
}
if( port_lock(p_lockdir, state.modemport) )
if( state.modemport )
{
if( port_lock(p_lockdir, state.modemport) == 0 ) /* Successfuly locked port */
{
rc = call_system_modem();
port_unlock(p_lockdir, state.modemport);
}
else
{
errmsg = "cannot lock modem port";
gotoexit(BFERR_PORTBUSY);
}
}
else /* Successfuly locked port */
else
{
rc = call_system_modem();
port_unlock(p_lockdir, state.modemport);
errmsg = "unable to get modem port";
}
}
else
if( rc )
{
rc = call_system_tcpip();
log("no connection effort was successful");
}
exit:

@ -31,7 +31,7 @@
/* On success: zero (state.session is handshake type) */
/* On error: non-zero (state.session set to UNKNOWN) */
/* ------------------------------------------------------------------------- */
int session_init_outgoing(void)
int session_init_outgoing()
{
int c = 0;
int tries = 0;
@ -72,8 +72,10 @@ int session_init_outgoing(void)
/*
* Put CR until any character received
*/
if( PUTCHAR('\r') < 0 || FLUSHOUT() < 0 )
if( PUTCHAR('\r') < 0 || FLUSHOUT() < 0 ) {
log("error: output");
return 1;
}
while( !CHARWAIT(1) )
{
@ -83,8 +85,10 @@ int session_init_outgoing(void)
return 1;
}
if( PUTCHAR('\r') < 0 || FLUSHOUT() < 0 )
if( PUTCHAR('\r') < 0 || FLUSHOUT() < 0 ) {
log("error: output");
return 1;
}
}
#ifdef DEBUG
@ -122,17 +126,27 @@ int session_init_outgoing(void)
{
DEB((D_HSHAKE, "tx_sendsync: resyncing"));
if( canemsi && PUTSTR("**EMSI_INQC816**EMSI_INQC816") < 0 )
if( canemsi && PUTSTR("**EMSI_INQC816**EMSI_INQC816") < 0 ) {
log("error: output");
return 1;
if( canyoohoo && PUTCHAR(YOOHOO) < 0 )
}
if( canyoohoo && PUTCHAR(YOOHOO) < 0 ) {
log("error: output");
return 1;
if( canftsc && PUTCHAR(TSYNC) < 0 )
}
if( canftsc && PUTCHAR(TSYNC) < 0 ) {
log("error: output");
return 1;
if( canemsi && PUTCHAR('\r') < 0 )
}
if( canemsi && PUTCHAR('\r') < 0 ) {
log("error: output");
return 1;
}
if( FLUSHOUT() < 0 )
if( FLUSHOUT() < 0 ) {
log("error: flush");
return 1;
}
timer_set(&sync_timer, OUTGOING_SYNC_TIMER);
}
@ -260,10 +274,14 @@ int session_init_outgoing(void)
state.session = SESSION_EMSI;
if( PUTSTR("**EMSI_INQC816\r") < 0
|| PUTSTR("**EMSI_INQC816\r") < 0 )
|| PUTSTR("**EMSI_INQC816\r") < 0 ) {
log("error: output");
return 1;
if( FLUSHOUT() < 0 )
}
if( FLUSHOUT() < 0 ) {
log("error: output");
return 1;
}
return 0;
}
@ -281,15 +299,19 @@ int session_init_outgoing(void)
sleep(3);
if( PUTSTR("**EMSI_INQC816\r") < 0
|| FLUSHOUT() < 0 )
|| FLUSHOUT() < 0 ) {
log("error: flush");
return 1;
}
/* Wait for a password prompt */
sleep(2);
if( PUTSTR("**EMSI_INQC816\r") < 0
|| FLUSHOUT() < 0 )
|| FLUSHOUT() < 0 ) {
log("error: output");
return 1;
}
timer_set(&sync_timer, OUTGOING_SYNC_TIMER);
}
@ -314,6 +336,7 @@ int session_init_outgoing(void)
c, string_printable(buf_emsi)));
}
}
//log("session_init_outgoing: end loop");
return 1;
}
@ -325,7 +348,7 @@ int session_init_outgoing(void)
/* */
/* TODO: It is not working yet, it only reports about EMSI requests.. (1) */
/* ------------------------------------------------------------------------- */
int session_init_incoming(void)
int session_init_incoming()
{
int c = 0;
int pos = 0;
@ -345,42 +368,64 @@ int session_init_incoming(void)
state.session = SESSION_UNKNOWN;
if( (options & OPTIONS_NO_EMSI) != OPTIONS_NO_EMSI )
//log("init");
if( (options & OPTIONS_NO_EMSI) != OPTIONS_NO_EMSI ) {
//log("can emsi");
canemsi = TRUE;
if( (options & OPTIONS_NO_YOOHOO) != OPTIONS_NO_YOOHOO )
}
if( (options & OPTIONS_NO_YOOHOO) != OPTIONS_NO_YOOHOO ) {
//log("can yahoo");
canyoohoo = TRUE;
if( (options & OPTIONS_NO_FTS1) != OPTIONS_NO_FTS1 )
}
if( (options & OPTIONS_NO_FTS1) != OPTIONS_NO_FTS1 ) {
//log("can ftsc");
canftsc = TRUE;
}
yoohoo_need = canemsi ? 2 : 1;
tsync_need = (canemsi || canyoohoo) ? 2 : 1;
if( PUTCHAR('\r') < 0 )
if( PUTCHAR('\r') < 0 ) {
log("error: cannot put char");
return 1;
}
/*
* Output banner
*/
if( canemsi && PUTSTR("**EMSI_REQA77E\r") < 0 )
if( canemsi && PUTSTR("**EMSI_REQA77E\r") < 0 ) {
log("error: cannot put banner");
return 1;
}
if( state.connstr )
{
/* Show connect string */
if( PUTCHAR('[') < 0 )
if( PUTCHAR('[') < 0 ) {
log("error: cannot put ']'");
return 1;
if( PUTSTR(state.connstr) < 0 )
}
if( PUTSTR(state.connstr) < 0 ) {
log("error: cannot put connstr");
return 1;
if( PUTSTR("]\n") < 0 )
}
if( PUTSTR("]\n") < 0 ) {
log("error: cannot put ']'");
return 1;
}
}
if( PUTSTR(BF_BANNERVER) < 0 || PUTCHAR(' ') < 0
|| PUTSTR(BF_COPYRIGHT) < 0 || PUTCHAR('\n') < 0 )
|| PUTSTR(BF_COPYRIGHT) < 0 || PUTCHAR('\n') < 0 ) {
log("session_init_incoming error: output");
return 1;
}
if( FLUSHOUT() < 0 )
if( FLUSHOUT() < 0 ) {
log("session_init_incoming error: flush");
return 1;
}
/* Start timers */
timer_set(&mast_timer, INCOMING_MAST_TIMER);
@ -390,6 +435,8 @@ int session_init_incoming(void)
* Determine supported handshakes on called system
* (support for FTS-1, YooHoo, EMSI)
*/
//log("begin loop");
while(1)
{
if( timer_expired(mast_timer) )
@ -404,11 +451,15 @@ int session_init_incoming(void)
{
DEB((D_HSHAKE, "rx_init: resyncing"));
if( canemsi && PUTSTR("**EMSI_REQA77E\r") < 0 )
if( canemsi && PUTSTR("**EMSI_REQA77E\r") < 0 ) {
log("session_init_incoming error: output");
return 1;
}
if( FLUSHOUT() < 0 )
if( FLUSHOUT() < 0 ) {
log("session_init_incoming error: flush");
return 1;
}
timer_set(&sync_timer, INCOMING_SYNC_TIMER);
}

@ -320,22 +320,24 @@ int session_set_inbound(void)
if( conf_boolean(cf_split_inbound) )
{
char buf[PATH_MAX+31];
if( state.node.addr.point ) {
snprintf( buf, PATH_MAX, "%s%d:%d/%d.%d/%s-in/",
//if( state.node.addr.point ) {
// snprintf( buf, PATH_MAX, "%s%d:%d/%d.%d/%s-in/",
snprintf( buf, PATH_MAX, "%s%d.%d.%d.%d/%s-in/",
p_inb,
state.node.addr.zone,
state.node.addr.net,
state.node.addr.node,
state.node.addr.point,
state.protected? "pwd": "unchecked" );
} else {
snprintf( buf, PATH_MAX, "%s%d:%d/%d/%s-in/",
/*} else {
// snprintf( buf, PATH_MAX, "%s%d:%d/%d/%s-in/",
snprintf( buf, PATH_MAX, "%s%d.%d.%d/%s-in/",
p_inb,
state.node.addr.zone,
state.node.addr.net,
state.node.addr.node,
state.protected? "pwd": "unchecked" );
}
} */
log("inbound: %s", buf);
state.inbound = (char*)xstrcpy(buf);
snprintf( buf, PATH_MAX+30, "/bin/mkdir -p %s -m 700", state.inbound ); /* 30 additional chars allowed */
@ -804,6 +806,7 @@ int session(void)
/*
* Log expected traffic
*/
session_traffic();
init_protinfo(&pi, state.caller);
@ -854,6 +857,7 @@ int session(void)
/*
* Do session clenup (remove temp. files, etc.)
*/
(void)p_session_cleanup(&pi, (rc == BFERR_NOERROR));
if( rc == BFERR_NOERROR )
@ -898,9 +902,11 @@ int session(void)
*/
if( (p = conf_string(cf_run_after_session)) )
session_run_command(p);
}
exit:
state.session_rc = rc;
session_update_history(&traff_send, &traff_recv, rc);

@ -170,20 +170,31 @@ typedef signed char SINT8;
typedef struct {
bool daemon; /* Run as daemon? */
bool quit; /* Quit from daemon */
bool dontcall; /* -m key */
bool usestdio; /* Session on stdin and stdout */
int inetd; /* Called from inetd? */
int force; /* Force call? */
int hiddline; /* Hidden line number (0,1..) */
char *confname; /* Use this config instead def. */
char *incname; /* Include this config */
char *phone; /* Forced phone number */
char *iaddr; /* Forced IP address */
char *connect; /* Connect string */
char *device; /* Forced device name */
int stype; /* Handshake type in slave mode */
char *iphost; /* Forced IP address */
char *ipproto; /* proto to use over TCP/IP */
int stype; /* Handshake type in slave (answer) mode */
int runmode; /* concluded runmode */
s_falist *addrlist;
} s_bforce_opts;
#define MODE_UNDEFINED (0)
#define MODE_CALL_DEFAULT (1)
#define MODE_CALL_MODEM (2)
#define MODE_CALL_IP (3)
#define MODE_CALL_STDIO (4)
#define MODE_ANSWER (5)
#define MODE_DAEMON (6)
/*
* Global variables
*/

@ -82,7 +82,8 @@ enum nodelist_limit
BNI_MAXLOCATION = 48,
BNI_MAXSYSOP = 48,
BNI_MAXPHONE = 48,
BNI_MAXFLAGS = 120
BNI_MAXHOST = 200,
BNI_MAXFLAGS = 200
};
/*
@ -148,6 +149,10 @@ typedef struct node
char phone[BNI_MAXPHONE+1];
long speed;
char flags[BNI_MAXFLAGS+1];
bool do_binkp;
bool do_ifcico;
bool do_telnet;
char host[BNI_MAXHOST+1];
s_timevec worktime;
}
s_node;

@ -176,8 +176,8 @@ void init_state(s_state *pstate);
void deinit_state(s_state *pstate);
/* s_init.c */
int session_init_outgoing(void);
int session_init_incoming(void);
int session_init_outgoing();
int session_init_incoming();
/* s_main.c */
extern s_state state;
@ -209,7 +209,7 @@ int session(void);
/* sess_call.c */
int call_system(s_faddr addr, const s_bforce_opts *opts);
int call_system_modem(void);
int call_system_tcpip(void);
int call_system_tcpip(int callwith);
/* sess_answ.c */
int answ_system(e_session type, char *connstr, int inetd);

@ -0,0 +1,14 @@
#!/bin/sh
TOOLCHAIN=$HOME/OpenWRT/OpenWrt-Toolchain-ar71xx-for-mips_r2-gcc-4.3.3+cs_uClibc-0.9.30.1/toolchain-mips_r2_gcc-4.3.3+cs_uClibc-0.9.30.1
PATH=$PATH:$TOOLCHAIN/usr/bin
PREFIX=mips-openwrt-linux
CPP=$PREFIX-cpp
CC=$PREFIX-gcc
#CFLAGS=
export PATH CC CPP
#./configure --prefix=/opt/bforce --host=mips-openwrt-linux --disable-syslog
Loading…
Cancel
Save