/*////////////////////////////////////////////////////////////////////////
Copyright (c) 1997-2000 Yutaka Sato and ETL,AIST,MITI
Copyright (c) 2001-2008 National Institute of Advanced Industrial Science and Technology (AIST)
AIST-Product-ID: 2000-ETL-198715-01, H14PRO-049, H15PRO-165, H18PRO-443

Permission to use this material for noncommercial and/or evaluation
purpose, copy this material for your own use, and distribute the copies
via publicly accessible on-line media, without fee, is hereby granted
provided that the above copyright notice and this permission notice
appear in all copies.
AIST MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY OF THIS
MATERIAL FOR ANY PURPOSE.  IT IS PROVIDED "AS IS", WITHOUT ANY EXPRESS
OR IMPLIED WARRANTIES.
/////////////////////////////////////////////////////////////////////////
Content-Type:	program/C; charset=US-ASCII
Program:	env.c
Author:		Yutaka Sato <ysato@etl.go.jp>
Description:
History:
	970814	extracted from delegated.c
//////////////////////////////////////////////////////////////////////#*/
#include "config.h"
#include "delegate.h"
#include "param.h"
#include "fpoll.h"
#include "file.h"
#include <stdlib.h>

int  main_argc;
const char **main_argv;
extern char **environ;

scanPFUNCP param_scanner(PCStr(param));

typedef struct {
	int   ee_ext_argc;
  const	char *ee_ext_argv[MAX_ARGC]; /**/
	int   ee_extovw_argc;
  const	char *ee_extovw_argv[MAX_ARGC]; /**/
	int   ee_gen_envx;
  const	char *ee_gen_environ[32]; /**/
  const	char *ee_ext_environ[MAX_ARGC]; /**/
	int   ee_bin_argc;
  const char *ee_bin_argv[MAX_ARGC]; /**/
	int   ee_bin_argGot;
} Envs;
static Envs *envs;
#define ext_argc	envs->ee_ext_argc
#define ext_argv	envs->ee_ext_argv
#define extovw_argc	envs->ee_extovw_argc
#define extovw_argv	envs->ee_extovw_argv
#define gen_envx	envs->ee_gen_envx
#define gen_environ	envs->ee_gen_environ
#define ext_environ	envs->ee_ext_environ
#define bin_argc	envs->ee_bin_argc
#define bin_argv	envs->ee_bin_argv
#define bin_argGot	envs->ee_bin_argGot

void minit_envs(){
	if( envs == 0 )
		envs = NewStruct(Envs);
}

int getBconfig(int ac,char *av[]);
const char *getEnvBin(PCStr(name)){
	if( bin_argGot == 0 ){
		bin_argGot = 1;
		bin_argc = getBconfig(elnumof(bin_argv),(char**)bin_argv);
	}
	return getv(bin_argv,name);
}
void scan_DGPATH(PCStr(path));
void loadViaImp(Connection *Conn){
	int ai;
	const char *arg;
	const char *dgpath = 0;

	getEnvBin("");
	for( ai = 0; ai < bin_argc; ai++ ){
		arg = bin_argv[ai];
		if( strstr(arg,"+=") ){
			if( dgpath == 0 ){
				if( (dgpath = getv(bin_argv,P_DGPATH)) == 0 )
					dgpath = DELEGATE_DGPATH;
				scan_DGPATH(dgpath);
			}
			scan_arg1(Conn,NULL,arg);
		}
	}
}

int DELEGATE_EXTOVW;
void DELEGATE_clearEnv()
{
	extovw_argc = 0;
}
const char *DELEGATE_getEnv(PCStr(name))
{
	return DELEGATE_getEnvX(name,PARAM_ALL);
}
const char *DELEGATE_getEnvX(PCStr(name),int where)
{	const char *value;
	CStr(xname,64);

	if( where & PARAM_GENENV )
	if( value = getv(gen_environ,name) )
		return value;

	if( where & PARAM_EXTOVW)
	if( value = getv(extovw_argv,name) )
		return value;

	if( where & PARAM_MAINARG)
	if( value = getv(main_argv,name) )
		return value;

	if( where & PARAM_EXTARG)
	if( value = getv(ext_argv,name) )
		return value;

	sprintf(xname,"DG_%s",name);
	if( where & PARAM_DGENV)
	if( value = getenv(xname) )
		return value;

	if( where & PARAM_ENV)
	if( value = getenv(name) )
		return value;
	/*
	return getenv(name);
	*/

	if( value = getEnvBin(name) )
		return value;

	return 0;
}
const char *getEnvBin1st(PCStr(name)){
	const char *env;
	if( env = getEnvBin(name) )
		return env;
	return DELEGATE_getEnv(name);
}

const char *getMainArg(PCStr(where),PCStr(name)){
	return DELEGATE_getEnv(name);
}

void dumpEnv(){
	int ai;
	for( ai = 0; gen_environ[ai]; ai++ )
		printf("GEN[%d] %s\n",ai,gen_environ[ai]);
	for( ai = 0; ai < extovw_argc; ai++ )
		printf("OVW[%d] %s\n",ai,extovw_argv[ai]);
	for( ai = 0; ai < main_argc; ai++ )
		printf("MAI[%d] %s\n",ai,main_argv[ai]);
	for( ai = 0; ai < ext_argc; ai++ )
		printf("EXT[%d] %s\n",ai,ext_argv[ai]);
	for( ai = 0; environ[ai]; ai++ )
		printf("ENV[%d] %s\n",ai,environ[ai]);
}
int encrypt_argv(int ac,char *av[]);
void encrypt_args(){
	encrypt_argv(main_argc,(char**)main_argv);
	encrypt_argv(ext_argc,(char**)ext_argv);
}
static int findarg1(int ac,const char *av[],PCStr(pat),PVStr(arg)){
	int ai;
	int len = strlen(pat);
	for( ai = 0; ai < ac; ai++ ){
		if( strneq(av[ai],pat,len) ){
			if( arg ){
				strcpy(arg,av[ai]);
			}
			return ai;
		}
	}
	return -1;
}
int get_mainarg(PCStr(pat),PVStr(arg)){
	if( 0 <= findarg1(main_argc,main_argv,pat,BVStr(arg)) ) return 1;
	if( 0 <= findarg1(ext_argc,ext_argv,pat,BVStr(arg)) ) return 1;
	return 0;
}
int DELEGATE_copyEnv(int mac,const char *av[],int ac,PCStr(path),PVStr(abuff))
{	int ai;
	CStr(hosts,0x4000);
	CStr(port,PORTSSIZE);
	refQStr(ap,abuff); /**/

	if( mac-1 <= ac )
		goto EXIT;
	if( lVERB() ){
		av[ac++] = "-vv";
	}else{
		printServPort(AVStr(port),"",0);
		if( port[0] == 0 ){
			/* this can occur with -x option on Unix, port is
			 * not set yet, don't disable LOGFILE by this
			 */
		}else{
		sprintf(ap,"%s=%s",P_LOGFILE,port);
		av[ac++] = ap;  ap += strlen(ap) + 1;
		}
	}

	if( mac-1 <= ac )
		goto EXIT;
	sprintf(ap,"%s=%s",P_EXEC_PATH,path);
	av[ac++] = ap; ap += strlen(ap) + 1;

	for( ai = 0; ai < ext_argc; ai++ ){
		if( mac-1 <= ac )
			goto EXIT;
		av[ac++] = ext_argv[ai];
	}

	for( ai = 1; ai < main_argc; ai++ ){
		if( mac-1 <= ac )
			goto EXIT;
		if( main_argv[ai] )
			av[ac++] = main_argv[ai];
	}

	for( ai = 0; ai < extovw_argc; ai++ ){
		if( mac-1 <= ac )
			goto EXIT;
		av[ac++] = extovw_argv[ai];
	}

	for( ai = 0; ai < gen_envx; ai++ ){
		if( mac-1 <= ac )
			goto EXIT;
		av[ac++] = gen_environ[ai];
	}

	if( mac-1 <= ac )
		goto EXIT;
	if( dump_HOSTS(AVStr(hosts)) ){
		sprintf(ap,"%s=%s",P_HOSTS,hosts);
		Verbose("%s\n",ap);
		av[ac++] = ap; ap += strlen(ap) + 1;
	}
EXIT:
	return ac;
}
int DELEGATE_copyEnvPM(int mac,const char *dav[],PCStr(name))
{	int ac;

	ac = 0;
	ac += copy_param(name,mac-ac,&dav[ac],(const char**)environ);
	ac += copy_param(name,mac-ac,&dav[ac],ext_argv);
	ac += copy_param(name,mac-ac,&dav[ac],&main_argv[1]);
	ac += copy_param(name,mac-ac,&dav[ac],gen_environ);
	return ac;
}

int dump_main(int ac,const char *av[])
{	int ai;
	const char *nam;
	const char *val;
	CStr(valb,256);

	for( ai = 1; ai < ac; ai++ ){
		nam = av[ai];
		if( strcmp(nam,"DGROOT") == 0 ){
			val = DELEGATE_DGROOT;
		}else
		if( strcmp(nam,"OWNER") == 0 ){
			sprintf(valb,"#%d/#%d",getuid(),getgid());
			val = valb;
		}else
		if( strcmp(nam,"ADMIN") == 0 ){
			val = getADMIN();
		}else{
			val = DELEGATE_getEnv(nam);
		}
		printf("%s\n",val?val:"(none)");
	}
	exit(0);
	return 0;
}

/*
static const char *getEnvT(PCStr(name))
{	const char *body;
	if( body = getEnv(name) )
		if( body[-1] == '=' )
			return body - strlen(name) - 1;
		else	return body - strlen(name);
	return 0;
}
*/

void DELEGATE_addEnvExt(PCStr(env))
{
	if( lVERB() || lARGDUMP() ){
		if( DELEGATE_EXTOVW )
			fprintf(stderr,"<%d> %s\n",extovw_argc,env);
		else	fprintf(stderr,"<%d> %s\n",ext_argc,env);
	}
	if( DELEGATE_EXTOVW ){
		if( elnumof(extovw_argv) <= extovw_argc ){
			syslog_ERROR("too many args: %s\n",env);
		}else{
			extovw_argv[extovw_argc++] = StrAlloc(env);
		}
	}else{
		if( elnumof(ext_argv) <= ext_argc ){
			syslog_ERROR("too many args: %s\n",env);
		}else{
			ext_argv[ext_argc++] = StrAlloc(env);
		}
	}
}
void DELEGATE_pushEnv(PCStr(name),PCStr(value))
{	CStr(env,1024);

	sprintf(env,"%s=%s",name,value);
	if( elnumof(gen_environ) <= gen_envx ){
		syslog_ERROR("too many args: %s\n",env);
	}else{
		gen_environ[gen_envx++] = StrAlloc(env);
	}
}
typedef struct {
	Connection *sv_Conn;
	IFUNCP	sv_func;
  const char	*sv_arg;
	int	sv_ign_include;
} SvArg;
static int scanenv1(SvArg *sva,PCStr(val))
{
	if( strncmp(val,INC_SYM,INC_SYM_LEN) == 0 )
		return 0;
	if( strstr(val,":+=") || strstr(val,",+=") )
		return 0;
	else	return (*sva->sv_func)(sva->sv_Conn,val,sva->sv_arg);
}
int DELEGATE_scanEnv(Connection *Conn,PCStr(name),scanPFUNCP func,...)
{	int nhit;
	SvArg sva;
	const char *arg;
	VARGS(1,func);
	arg = va[0];

	nhit = 0;
	sva.sv_Conn = Conn;
	sva.sv_func = (IFUNCP)func;
	sva.sv_arg = arg;
	nhit += scanv((const char**)environ,name,(iFUNCP)scanenv1,(void*)&sva);
	nhit += scanv(ext_argv,name,(iFUNCP)scanenv1,(void*)&sva);
	nhit += scanv(main_argv,name,(iFUNCP)scanenv1,(void*)&sva);
	nhit += scanv(extovw_argv,name,(iFUNCP)scanenv1,(void*)&sva);
	nhit += scanv(gen_environ,name,(iFUNCP)scanenv1,(void*)&sva);
	nhit += scanv(bin_argv,name,(iFUNCP)scanenv1,(void*)&sva);
	return nhit;
}

const char *parameq(PCStr(param),PCStr(name));
static void svxlog(PCStr(fmt),int ai,PCStr(arg1)){
	const char *pv;
	if( lSECRET() ){
	}else{
		if( pv = parameq(arg1,"MYAUTH") ){ arg1 = "MYAUTH="; }
		if( pv = parameq(arg1,"PASSWD") ){ arg1 = "PASSWD="; }
		if( pv = parameq(arg1,"CRYPT" ) ){ arg1 = "CRYPT="; }
	}
	if( ai < 0 )
		sv0log(fmt,arg1);
	else	sv0log(fmt,ai,arg1);
}
#define CFput0(fp,fmt,msg) {\
	if( fp != NULL ) fprintf(fp,fmt,msg); else svxlog(fmt,-1,msg); \
	leng += strlen(msg); \
}
#define CFput(fp,fmt,ai,msg) {\
	if( fp != NULL ) fprintf(fp,fmt,ai,msg); else svxlog(fmt,ai,msg); \
	leng += strlen(msg); \
}
int DELEGATE_dumpEnvX(FILE *fp,int genalso,int imPM,int showidx);
int DELEGATE_dumpEnv(FILE *fp,int genalso,int imPM)
{
	return DELEGATE_dumpEnvX(fp,genalso,imPM,1);
}
int DELEGATE_dumpEnvX(FILE *fp,int genalso,int imPM,int showidx)
{	int ai;
	const char *env;
	int leng = 0;

	if( fp != NULL && !imPM ){
		CStr(port,PORTSSIZE);
		printServPort(AVStr(port),"-P",genalso);
		fprintf(fp,"%s\n",port);
	}

	for( ai = 0; env = environ[ai]; ai++ )
	if( 0 <= check_param(env,0) )
		if( !showidx ) CFput0(fp,"env %s\n",env) else
		CFput(fp,"env[%d] %s\n",ai,env);

	for( ai = 0; ai < ext_argc; ai++ )
		if( !showidx ) CFput0(fp,"ext %s\n",ext_argv[ai]) else
		CFput(fp,"ext[%d] %s\n",ai,ext_argv[ai]);

	for( ai = 1; ai < main_argc; ai++ )
	if( 0 <= check_param(main_argv[ai],0) )
		if( !showidx ) CFput0(fp,"arg %s\n",main_argv[ai]) else
		CFput(fp,"arg[%d] %s\n",ai,main_argv[ai]);

	if( genalso )
	for( ai = 0; gen_environ[ai]; ai++ )
		if( !showidx ) CFput0(fp,"gen %s\n",gen_environ[ai]) else
		CFput(fp,"gen[%d] %s\n",ai,gen_environ[ai]);

	return leng;
}


/*
 * inporting configuration parameters
 */
int param_file = -1;
int param_mtime = 0;

void new_param_file(PCStr(path))
{	FILE *fp;

	if( 0 <= param_file )
		return;
	fp = TMPFILE("PARAM_FILE");
	/*
	 * it should be a visible file under ETCDIR or ADMDIR ...
	 */
	param_file = dup(fileno(fp));
	fclose(fp);
	param_mtime = file_mtime(param_file);
}
int add_params(Connection *Conn,FILE *tc,PCStr(command))
{	FILE *fp;
	int pid;
	CStr(com,1024);
	CStr(param,1024);

	/*
	 * must check accees right here...
	 */

	if( param_file < 0 ){
		fprintf(tc,"500 no parameter file\r\n");
		return -1;
	}

	com[0] = param[0] = 0;
	Xsscanf(command,"%s %[^\r\n]",AVStr(com),AVStr(param));

	/*
	 * param may be +=URL
	 */

	if( com[0] == 0 || param[0] == 0 ){
		fp = fdopen(dup(param_file),"r");
		fseek(fp,0,0);
		fputs("200 list of inported parameters follows:\r\n",tc);
		copyfile1(fp,tc);
		fputs(".\r\n",tc);
		fclose(fp);
		return 0;
	}
	if( check_param(param,0) < 0 ){
		fprintf(tc,"500 unknown parameter: %s\r\n",param);
		return -1;
	}
	if( lock_exclusiveTO(param_file,2000,NULL) != 0 ){
		fprintf(tc,"500 cannot lock parameter file\r\n");
		return -1;
	}
	pid = getpid();
	fp = fdopen(dup(param_file),"w");
	fprintf(fp,"%d %s\r\n",pid,param);
	fclose(fp);

	sv1log("#### PARAM INPORTED: %d %s\n",pid,param);
	fprintf(tc,"200 ok.\r\n");
	return 0;
}
void load_params(Connection *Conn)
{	FILE *fp;
	CStr(line,1024);
	CStr(param,1024);
	int mtime,pid;

	if( param_file < 0 )
		return;
	mtime = file_mtime(param_file);
	if( mtime == param_mtime )
		return;
	param_mtime = mtime;
	sv1log("#### PARAM updated\n");

	fp = fdopen(dup(param_file),"r");
	fseek(fp,0,0);
	while( fgets(line,sizeof(line),fp) ){
		Xsscanf(line,"%d %[^\r\n]",&pid,AVStr(param));
		sv1log("#### %d %s\n",pid,param);
		if( strncmp(param,"MOUNT=",6) == 0 ){
			scan_MOUNT(Conn,param+6);
			init_mtab();
		}
	}
	fclose(fp);
}


extern int DELAY_REJECT_S;
extern int DELAY_UNKNOWN_S;
extern int DELAY_REJECT_P;
extern int DELAY_UNKNOWN_P;
extern int DELAY_ERROR;

static scanListFunc delay1(PCStr(dspec),Connection *Conn)
{	CStr(what,128);
	int delay;
	int *iaddr;

	delay = 0;
	Xsscanf(dspec,"%[^:]:%d",AVStr(what),&delay);

	iaddr = 0;
	if( strcaseeq(what,"reject")    ) iaddr = &DELAY_REJECT_S; else
	if( strcaseeq(what,"unknown")   ) iaddr = &DELAY_UNKNOWN_S; else
	if( strcaseeq(what,"reject_p")  ) iaddr = &DELAY_REJECT_P; else
	if( strcaseeq(what,"unknown_p") ) iaddr = &DELAY_UNKNOWN_P; else
	if( strcaseeq(what,"error")     ) iaddr = &DELAY_ERROR; else
	{
		sv1tlog("ERROR: unknown DELAY=%s\n",what);
	}
	if( iaddr ){
		xmem_push(iaddr,sizeof(int),"DELAY",NULL);
		*iaddr = delay;
	}
	return 0;
}
void scan_DELAY(Connection *Conn,PCStr(sdelay))
{
	scan_commaList(sdelay,0,scanListCall delay1,Conn);
}

extern int MAX_ERESTART;
/*
extern int MAX_DELEGATE;
*/
extern int MAX_DELEGATEsta;
#define MAX_DELEGATE MAX_DELEGATEsta
extern int MAX_SERVICE;
extern int STANDBY_MAX;
extern int FDSET_MAX;
extern int HTTP_CKA_MAXREQ;
extern int HTTP_CKA_PERCLIENT;
extern int MAX_CC;
extern int MAXCONN_PCH;
extern int MAX_BUFF_SOCKRECV;
extern int MAX_BUFF_SOCKSEND;
extern int RANDSTACK_RANGE;
extern int RANDSTACK_UNIT;
extern int RANDFD_RANGE;
extern int RANDENV_RANGE;
extern int UDPRELAY_MAXASSOC;
extern int CON_RETRY;
int SERVER_RESTART_SERNO;

static scanListFunc maxima1(PCStr(maxima),Connection *Conn)
{	CStr(name,128);
	IStr(unit,32);
	CStr(val,32);
	int num;
	int *addr;

	/*
	if( Xsscanf(maxima,"%[^:]:%d",AVStr(name),&num) != 2 ){
	*/
	if( Xsscanf(maxima,"%[^:]:%d%s",AVStr(name),&num,AVStr(unit)) < 2 ){
		ERRMSG("DeleGate/%s: ERROR syntax MAXIMA=%s\n",
			DELEGATE_ver(),maxima);
		return 0;
	}
	if( unit[0] ){
		sprintf(val,"%d%s",num,unit);
		num = kmxatoi(val);
	}

	addr = 0;
	if( streq(name,"erestart") )	addr = &MAX_ERESTART; else
	if( streq(name,"randstack") )	addr = &RANDSTACK_RANGE; else
	if( streq(name,"randfd") )	addr = &RANDFD_RANGE; else
	if( streq(name,"randenv") )	addr = &RANDENV_RANGE; else
	if( streq(name,"fdset") )	addr = &FDSET_MAX; else
	if( streq(name,"delegated") )	addr = &MAX_DELEGATE; else
	if( streq(name,"restart") )	addr = &SERVER_RESTART_SERNO; else
	if( streq(name,"standby") )     addr = &STANDBY_MAX; else
	if( streq(name,"ftpcc") )	addr = &MAX_CC; else
	if( streq(name,"nntpcc") )	addr = &MAX_CC; else
	if( streq(name,"svcc") )	addr = &MAX_CC; else
	if( streq(name,"listen") )	addr = &DELEGATE_LISTEN; else
	if( streq(name,"sockrecv") )	addr = &MAX_BUFF_SOCKRECV; else
	if( streq(name,"socksend") )	addr = &MAX_BUFF_SOCKSEND; else
	if( streq(name,"winmtu") )	addr = &WIN_MTU; else
	if( streq(name,"service") )	addr = &MAX_SERVICE; else
	if( streq(name,"conpch") )	addr = &MAXCONN_PCH; else
	if( streq(name,"contry") )	addr = &CON_RETRY; else
	if( streq(name,"http-cka") )	addr = &HTTP_CKA_MAXREQ; else
	if( streq(name,"http-ckapch") )	addr = &HTTP_CKA_PERCLIENT; else
	if( streq(name,"udprelay") )	addr = &UDPRELAY_MAXASSOC; else
	{

		ERRMSG("DeleGate/%s: ERROR unknown MAXIMA=%s\n",
			DELEGATE_ver(),maxima);
	}

	if( addr ){
		xmem_push(addr,sizeof(int),"MAXIMA",NULL);
		*addr = num;
	}
	return 0;
}
void scan_MAXIMA(Connection *Conn,PCStr(maxima))
{
	scan_commaList(maxima,0,scanListCall maxima1,Conn);
}

extern int SHUTOUT_TIMEOUT;
extern int DNS_TIMEOUT;
extern int ACC_TIMEOUT;
extern int CON_TIMEOUT;
extern int LIN_TIMEOUT;
extern int IO_TIMEOUT;
extern int CC_TIMEOUT_FTP;
extern int CC_TIMEOUT_NNTP;
extern int CACHE_TAKEOVER;
extern int RSLV_INV_TIMEOUT;
extern int SILENCE_TIMEOUT; /* no transmission from server or client */
extern int HELLO_TIMEOUT;
extern int VSAP_TIMEOUT;
extern int ERROR_RESTART;
extern int SERVER_RESTART;
extern int SERVER_DEFREEZE;
extern int SERVER_TIMEOUT;
extern int STANDBY_TIMEOUT;
extern int SPAWN_TIMEOUT;
extern int NONCE_TIMEOUT;
extern double HTTP_WAIT_REQBODY;
extern double HTTP_TOUT_IN_REQBODY;
extern double HTTP_TOUT_CKA;
extern double HTTP_TOUT_CKA_MARGIN;
extern double SVHELLO_TIMEOUT;
extern double IDENT_TIMEOUT;
extern double CFISTAT_TIMEOUT;
extern double AUTHORIZER_TIMEOUT;
extern double WAITCHILD_TIMEOUT;
extern double BINDENTER_TIMEOUT;
extern double BIND_TIMEOUT;
extern double MAX_HTMUXSKEW;

static scanListFunc timeout1(PCStr(to),Connection *Conn)
{	CStr(name,128);
	CStr(period,128);
	double secs;
	double *daddr;
	int *iaddr;

	if( Xsscanf(to,"%[^:]:%s",AVStr(name),AVStr(period)) == 2 ){
		secs = Scan_period(period,'s',(double)0);
		daddr = 0;
		iaddr = 0;

		if( streq(name,"shutout"))   iaddr = &SHUTOUT_TIMEOUT; else
		if( streq(name,"hello"))     iaddr = &HELLO_TIMEOUT; else
		if( streq(name,"login"))     iaddr = &LOGIN_TIMEOUT; else
		if( streq(name,"dns") )	     iaddr = &DNS_TIMEOUT; else
		if( streq(name,"dnsinv") )   iaddr = &RSLV_INV_TIMEOUT; else
		if( streq(name,"vsapacc"))   iaddr = &VSAP_TIMEOUT; else
		if( streq(name,"acc") )	     iaddr = &ACC_TIMEOUT; else
		if( streq(name,"con") )	     iaddr = &CON_TIMEOUT; else
		if( streq(name,"lin") )	     iaddr = &LIN_TIMEOUT; else
		if( streq(name,"greeting"))  daddr = &SVHELLO_TIMEOUT; else
		if( streq(name,"ident"))     daddr = &IDENT_TIMEOUT; else
		if( streq(name,"rident"))    daddr = &RIDENT_TIMEOUT; else
		if( streq(name,"authorizer"))daddr = &AUTHORIZER_TIMEOUT; else
		if( streq(name,"cfistat"))   daddr = &CFISTAT_TIMEOUT; else
		if( streq(name,"silence"))   iaddr = &SILENCE_TIMEOUT; else
		if( streq(name,"io") )	     iaddr = &IO_TIMEOUT; else
		if( streq(name,"idle"))	     iaddr = &IO_TIMEOUT; else
		if( streq(name,"restart"))   iaddr = &SERVER_RESTART; else
		if( streq(name,"waitchild")) daddr = &WAITCHILD_TIMEOUT; else
		if( streq(name,"bindenter")) daddr = &BINDENTER_TIMEOUT; else
		if( streq(name,"bind"))      daddr = &BIND_TIMEOUT; else
		if( streq(name,"defreeze"))  iaddr = &SERVER_DEFREEZE; else
		if( streq(name,"erestart"))  iaddr = &ERROR_RESTART; else
		if( streq(name,"daemon"))    iaddr = &SERVER_TIMEOUT; else
		if( streq(name,"standby")  ) iaddr = &STANDBY_TIMEOUT; else
		if( streq(name,"spawn"))     iaddr = &SPAWN_TIMEOUT; else
		if( streq(name,"dgnonce")  ) iaddr = &NONCE_TIMEOUT; else
		if( streq(name,"takeover"))  iaddr = &CACHE_TAKEOVER; else
		if( streq(name,"ftpcc"))     iaddr = &CC_TIMEOUT_FTP; else
		if( streq(name,"nntpcc"))    iaddr = &CC_TIMEOUT_NNTP; else
		if( streq(name,"htmuxskew")) daddr = &MAX_HTMUXSKEW; else

	if( streq(name,"http-wait-qbody"))   daddr = &HTTP_WAIT_REQBODY; else
	if( streq(name,"http-poll-qbody"))   daddr = &HTTP_TOUT_IN_REQBODY; else
	if( streq(name,"http-cka"))          daddr = &HTTP_TOUT_CKA; else
	if( streq(name,"http-ckamg"))        daddr = &HTTP_TOUT_CKA_MARGIN; else
		{
			sv1tlog("ERROR: unknown TIMEOUT=%s\n",name);
		}

		if( daddr ){
			xmem_push(daddr,sizeof(double),"TIMEOUT",NULL);
			*daddr = secs;
		}
		if( iaddr ){
			xmem_push(iaddr,sizeof(int),"TIMEOUT",NULL);
			*iaddr = (int)secs;
		}
	}
	if( SERVER_TIMEOUT )
	if( SERVER_TIMEOUT < ACC_TIMEOUT || ACC_TIMEOUT == 0 )
		ACC_TIMEOUT = SERVER_TIMEOUT;

	return 0;
}
void scan_TIMEOUT(Connection *Conn,PCStr(timeouts))
{
	scan_commaList(timeouts,0,scanListCall timeout1,Conn);
}

typedef struct {
	char	*m_addr; /**/
	int	 m_size;
	char	*m_save; /**/
  const char	*m_what;
	iFUNCP	 m_func;
} Memory;

#define MAXLEV 8
typedef struct {
	Memory	*s_mem;
	int	 s_siz;
	int	 s_top;
} Stack;

static Stack mstack[MAXLEV]; /**/

#define mdebug	!lMEMPUSH() ? 0 : putLog0

int mem_push(int lev,PCStr(addr),int size,PCStr(what),iFUNCP func)
{	Stack *St;
	Memory *Me;
	int siz,top,mi;

	St = &mstack[lev];
	if( St->s_siz <= St->s_top ){
		siz = St->s_siz = St->s_siz + 32;
		if( St->s_siz ){
			St->s_mem = (Memory*)realloc(St->s_mem,siz*sizeof(Memory));
			for( mi = St->s_top; mi < siz; mi++ )
				St->s_mem[mi].m_save = 0;
		}else	St->s_mem = (Memory*)calloc(siz,sizeof(Memory));
	}
	top = St->s_top++;
	Me = &St->s_mem[top];
	if( Me->m_save != 0 ){
		if( Me->m_size < size ){
			free(Me->m_save);
			Me->m_save = 0;
		}
	}
	if( Me->m_save == 0 )
		Me->m_save = (char*)malloc(size);
	Me->m_addr = (char*)addr;
	Me->m_size = size;
	Me->m_what = what;
	Me->m_func = func;
	bcopy(addr,Me->m_save,size); /**/

	mdebug("{m} PUSH[%d][%d] %X -> %X (%d) %s\n",lev,top,
		Me->m_addr,Me->m_save,Me->m_size,Me->m_what);
	return top;
}
void mem_pop1(int lev)
{	Stack *St;
	Memory *Me;
	int mi;
	iFUNCP func;
	int diff;

	St = &mstack[lev];
	for( mi = St->s_top-1; 0 <= mi; mi-- ){
		Me = &St->s_mem[mi];
		diff = bcmp(Me->m_save,Me->m_addr,Me->m_size);
		if( func = Me->m_func )
			(*func)(Me->m_save,Me->m_addr,Me->m_size,Me->m_what);
		else	bcopy(Me->m_save,Me->m_addr,Me->m_size);

		mdebug("{m} POP%s[%d][%d] %X <- %X (%d) %s\n",diff?"!":"=",
			lev,mi,Me->m_addr,Me->m_save,Me->m_size,Me->m_what);
	}
	St->s_top = 0;
}
void mem_pops(int lev)
{	int li;

	mdebug("{m} POPS[%d]\n",lev);
	for( li = MAXLEV-1; lev <= li; li-- ){
		mem_pop1(li);
	}
}

/*
 * "(" [srcHostList] [":"[dstHostList] [":"[protList]]] ")"argument
 * AMAP=[srcHostList]:[dstHostList]:[protoList]:argument
 * conditional argument
 */

const char *skip_argcond(PCStr(arg))
{
	if( strncmp(arg,"(",1) == 0 ){
		if( arg = strstr(arg,")") )
			arg++;
	}
	return arg;
}

typedef struct {
  const	char	*ca_cond;
  const	char	*ca_arg;
  scanPFUNCP	 ca_scan; /* function to interpret the argument */
	int	 ca_src;
	int	 ca_dst;
} CondArg;
static CondArg condArg[32]; /**/
static int condArgX;

int add_condarg(PCStr(arg))
{	const char *dp;
	CStr(cond,1024);
	int cai;
	CondArg *Cp;

	if( *arg != '(' )
		return 0;
	dp = wordscanY(arg+1,AVStr(cond),sizeof(cond),"^)");
	if( *dp++ != ')' )
		return 0;
	if( *dp == 0 )
		return 0;
	if( elnumof(condArg) <= condArgX ){
		return 0;
	}
	cai = condArgX++;
	Cp = &condArg[cai];
	Cp->ca_cond = stralloc(cond);
	Cp->ca_src = makePathList("condarg",cond);
	Cp->ca_arg = stralloc(dp);
	Cp->ca_scan = param_scanner(dp);

	mdebug("{m} INIT[%s](%d) %s\n",cond,Cp->ca_src,dp);
	return 1;
}

extern int BREAK_STICKY;
extern int (*evalarg_func)(const char*,const char*);
static Connection *evalarg_Conn;

static int exec_condarg(PCStr(base),PCStr(arg),scanPFUNCP func)
{	const char *dp;
	Connection *Conn = evalarg_Conn;

	if( func ){
		if( dp = strchr(arg,'=') ){
			(*func)(evalarg_Conn,dp+1);
		}
		return 1;
	}else
	if( strneq(arg,"-v",2)
	 || strneq(arg,"-d",2)
	 || strneq(arg,"-W",2)
	){
		xmem_push(&LOG_type,sizeof(LOG_type),"-vX",NULL);
		xmem_push(&LOG_VERBOSE,sizeof(LOG_VERBOSE),"-vv",NULL);
		scan_arg1(Conn,NULL,arg);
		return 1;
	}
	return 0;
}
static int scan1(PCStr(base),PCStr(arg))
{	scanPFUNCP func;

	func = param_scanner(arg);
	exec_condarg(base,arg,func);
	return 0;
}
void scan_condargs(Connection *Conn)
{	CondArg *Cp;
	const char *arg;
	int cai;
	int match;

	match = 0;
	for( cai = 0; cai < condArgX; cai++ ){
		Cp = &condArg[cai];
		arg = Cp->ca_arg;
		if( Cp->ca_src )
		{
		/*
		if( !matchPath1(Cp->ca_src,"-",Client_Host,Client_Port) )
		*/
			const char *us;
			if( ClientAuth.i_user[0] )
				us = ClientAuth.i_user;
			else	us = "-";
			if( !matchPath1(Cp->ca_src,us,Client_Host,Client_Port) )
			continue;
			mdebug("{m} [%d]MATCH [%s]%s\n",cai,us,arg);
		}

		if( strneq(arg,"+=",2) ){
			evalarg_func = scan1;
			evalarg_Conn = Conn;
			load_script(NULL,NULL,arg+2);
			evalarg_func = 0; 
			continue;
		}

		if( match == 0 ){
			const char **sp;
			xmem_push(&extovw_argc,sizeof(int),"ext_argc",NULL);
			sp = &extovw_argv[extovw_argc]; /* end of array */
			xmem_push(sp,sizeof(char*),"ext_argv",NULL);
		}
		mdebug("{m} [%d]MATCH [%s]%s\n",extovw_argc,Client_Host,arg);
		match++;
		if( elnumof(extovw_argv) <= extovw_argc )
			syslog_ERROR("too many extovw_arg\n");
		else	extovw_argv[extovw_argc++] = (char*)arg;

		if( exec_condarg(NULL,arg,Cp->ca_scan) ){
		}else{
			sv1log("{m} Not supported (%s)%s\n",
				Cp->ca_cond,Cp->ca_arg);
			BREAK_STICKY = 1;
		}
	}
}

enum { ENV_SORT, ENV_ALL, ENV_OUT };
#define setOpt(opts,opt1)	(opts |= (1<<opt1))
#define getOpt(opts,opt1)	(opts & (1<<opt1))

static int acmp(void *a1,void *a2){
	return strcmp(*(char**)a1,*(char**)a2);
}
char **sortv(char **ov){
	char **ev;
	char *e1;
	int ei;
	char *out = 0;

	for( ei = 0; ov[ei]; ei++ );
	ev = (char**)malloc(sizeof(char*)*(ei+1));
	for( ei = 0; e1 = ov[ei]; ei++ )
		ev[ei] = e1;
	ev[ei] = 0;
	qsort(ev,ei,sizeof(char*),(sortFunc)acmp);
	return ev;
}

int ttyuid(int fd);
int env_main(int ac,const char *av[]){
	int ai,ei;
	const char *a1;
	char *e1;
	char **ev;
	int opts = 0;
	FILE *outf = stdout;
	CStr(who,128);

	for( ai = 0; ai < ac; ai++ ){
		a1 = av[ai];
		if( *a1 == '-' ){
			switch( a1[1] ){
				case 'a': setOpt(opts,ENV_ALL); break;
				case 's': setOpt(opts,ENV_SORT); break;
				case 'o':
					if( ai+1 < ac ){
						outf = fopen(av[++ai],"w");
						if( outf == 0 ){
							outf = stderr;
						}else{
							setOpt(opts,ENV_OUT);
						}
					}
					break;
			}
		}
	}
	ev = environ;
	if( getOpt(opts,ENV_SORT) ){
		ev = sortv(ev);
	}
	for( ei = 0; e1 = ev[ei]; ei++ ){
		fprintf(outf,"%s\n",e1);
	}
	if( ev != environ )
		free(ev);

	if( getOpt(opts,ENV_ALL) ){
		CStr(tmp,1024);
		getcwd(tmp,sizeof(tmp));
		fprintf(outf,"TTY: %d\n",ttyuid(0));
		fprintf(outf,"UID: %d\n",getuid());
		fprintf(outf,"EUID: %d\n",geteuid());
		fprintf(outf,"PWD: %s\n",tmp);
		fprintf(outf,"PPID: %d\n",getppid());
		dumpFds(outf);
	}
	return 0;
}

/*
 * 9.8.2 extracted from delegated.c {([
 */
int SERNO_MINOR();
int ismainthread();
int Getpid();

int incRequestSerno(Connection *Conn)
{
	return REQUEST_SERNO = ++RequestSerno;
}
int incServReqSerno(Connection *Conn)
{
	return SERVREQ_SERNO = ++ServReqSerno;
}

extern int NUM_FNSV;
extern int NUM_THSV;
extern int lock_ext;

extern char TIMEFORM_mdHMS0[];
extern char TIMEFORM_mdHMSd[];
extern char TIMEFORM_mdHMSc[];
extern char TIMEFORM_mdHMSm[];
extern char TIMEFORM_mdHMS4[];
extern char TIMEFORM_mdHMS5[];
extern char TIMEFORM_mdHMS6[];
static const char *LOG_timefmts[8] = {
	TIMEFORM_mdHMSc,
	TIMEFORM_mdHMS0,
	TIMEFORM_mdHMSd,
	TIMEFORM_mdHMSm,
	TIMEFORM_mdHMS4,
	TIMEFORM_mdHMS5,
	TIMEFORM_mdHMS6,
	"",
};
const char *LOG_timefmt = TIMEFORM_mdHMSc;
void setLogTimeFmtL(int fx){
	if( 0 <= fx && fx < elnumof(LOG_timefmts) ){
		LOG_timefmt = LOG_timefmts[fx];
	}
}
void setLogTimeFmt(PCStr(fmt)){
	int lx = 0;
	switch( *fmt ){
		case '0': case 0:   lx = 1; break;
		case '1': case 'd': lx = 2; break;
		case '2': case 'c': lx = 0; break;
		case '3': case 'm': lx = 3; break;
		case '4':           lx = 4; break;
		case '5':           lx = 5; break;
		case '6': case 'u': lx = 6; break;
		case '%':           lx = 7; LOG_timefmts[7] = stralloc(fmt);
				    break;
		default: fprintf(stderr,"UNKNOWN: -vT%s\n",fmt); break;
	}
	LOG_timefmt = LOG_timefmts[lx];
	LOG_type2 |= lx;
}
int getSessionThreadInfo(int agid,int *serno,int *reqno,int *svreu,Connection **Conn);
void LOG_makeTime(PVStr(buf),int now,int usec){
	refQStr(bp,buf);
	CStr(tms,64);

	if( lMEMUSAGE() ){
		CStr(mu,128);
		static CStr(prev,128);
		strfRusage(AVStr(mu),"(%d,%r)",3,NULL);
		if( !streq(prev,mu) ){
			sprintf(bp,"%s -- MEM.DIFF.\n",mu);
			bp += strlen(bp);
			strcpy(prev,mu);
		}
		strcpy(bp,mu);
		bp += strlen(bp);
	}
	StrftimeLocal(AVStr(tms),sizeof(tms),LOG_timefmt,now,usec);
	if( lSINGLEP() ){
		int sid,serno,reqno,svreu;
		sid = getSessionThreadInfo(0,&serno,&reqno,&svreu,0);
		sprintf(bp,"%s [%04X] %d+%d",tms,
			PRTID(getthreadid()),sid,serno);
		bp += strlen(bp);
		if( reqno ){
			sprintf(bp,"/%d",reqno);
			bp += strlen(bp);
		}
		strcpy(bp,": ");
		return;
	}

	if( (0 < LOGLEVEL || lTHREAD()) && !ismainthread() )
		sprintf(bp,"%s [%d.%X] %d+%d",tms,
			getpid(),getthreadid(),SERNO(),SERNO_MINOR());
	else	sprintf(bp,"%s [%d] %d+%d",tms,
			Getpid(),SERNO(),SERNO_MINOR());
	bp += strlen(bp);
	if( deleGateEnv != NULL ){
		if( REQUEST_SERNO || SERVREQ_SERNO ){
			sprintf(bp,"/%d",REQUEST_SERNO);
			bp += strlen(bp);
		}
		if( SERVREQ_SERNO ){
			sprintf(bp,"/%d",SERVREQ_SERNO);
			bp += strlen(bp);
		}
	}
	strcpy(bp,": ");
}

static int LOG_type_got;
int acceptExclusive();
void setupForSolaris()
{
	/* LOG_type is given by the parent in private-MASTER in the av[] */
	if( LOG_type_got || lLOGSHARED() )
		return;

	if( acceptExclusive() ){
		Verbose("ACCEPT EXCLUSION is ON by default.\n");
		if( (LOG_type & (L_FORK|L_EXEC)) == 0 ){
			if( LOG_type & L_LOCK )
				LOG_type &= ~L_LOCK;
			else	LOG_type |=  L_LOCK;
		}
	}
}

static void dumpLC(FILE *lfp,PCStr(wh),LogControl *lc){
	fprintf(lfp,"--LogCtrl %s [%08X %08X %08X]\n",wh,
		lc->lc_flags[0],lc->lc_flags[1],lc->lc_flags[2]);
	fflush(lfp);
}
int setupPeeping(Connection *XConn,PCStr(peepf)){
      switch( peepf[0] ){
	case '-':
		LOG_type3 &= ~(L_PEEPSV | L_PEEPCL);
		break;
	case 0:	LOG_type3 |= L_PEEPSV | L_PEEPCL; break;
	case 'q':
	  switch( peepf[1] ){
	    case   0: LOG_type3 |= L_PEEPCLDG | L_PEEPDGSV;
		break;
	    case 'c':
	    case 't': LOG_type3 |= L_PEEPCLDG; break;
	    case 's': LOG_type3 |= L_PEEPDGSV; break;
	  }
	  break;
	case 'r':
	  switch( peepf[1] ){
	    case   0: LOG_type3 |= L_PEEPSVDG | L_PEEPDGCL;
		break;
	    case 'c':
	    case 't': LOG_type3 |= L_PEEPDGCL; break;
	    case 's': LOG_type3 |= L_PEEPSVDG; break;
	  }
	  break;
	case 's':
	  switch( peepf[1] ){
	    case   0: LOG_type3 |= L_PEEPSV; break;
	    case 'r': LOG_type3 |= L_PEEPSVDG; break;
	    case 'q': LOG_type3 |= L_PEEPDGSV; break;
	  }
	  break;
	case 'c':
	case 't':
	  switch( peepf[1] ){
	    case   0: LOG_type3 |= L_PEEPCL; break;
	    case 'q': LOG_type3 |= L_PEEPCLDG; break;
	    case 'r': LOG_type3 |= L_PEEPDGCL; break;
	  }
	  break;
	}
	return 0;
}
void featuresED(PCStr(arg)){
	int dis = (arg[1] == 'D');
	int *addr = 0;
	int flag = 0;

	switch( arg[2] ){
	    case 'A':
	     switch( arg[3] ){
	      case 'P': addr = &LOG_type4; flag = L_NOAUTHPROXY; break;
		/*
	      case 'M': addr = &LOG_type4; flag = L_NOMITMAUTH; break;
		*/
	      case 'f': addr = &LOG_type4; flag = L_FORWPAUTH; dis = !dis;break;
	     }
	     break;
	    case 'C':
	     switch( arg[3] ){
	      case 'C': addr = &LOG_type4; flag = L_CCXCOOKIE; dis= !dis; break;
	      case 'S': addr = &LOG_type4; flag = L_UNSIGNEDCRC8; break;
	      default:	addr = &LOG_type3; flag = L_NOCACHE; break;
	     }
	     break;
	    case 'R':
	     switch( arg[3] ){
	      case 'u': addr = &LOG_type4; flag = L_HOSTSUPD; dis = !dis; break;
	     }
	     break;
	    case 'S':
	     switch( arg[3] ){
	      case 'p': addr = &LOG_type4; flag = L_NOSIGPIPE; break;
	     }
	     break;
	    case 'a':
	     switch( arg[3] ){
	      case 'o': addr = &LOG_type4; flag = L_ORIGDST; dis = !dis; break;
	     }
	     break;
	    case 'c':
	     switch( arg[3] ){
	      case 'p': addr = &LOG_type4; flag = L_CONNPARA; dis = !dis; break;
	      case 'q': addr = &LOG_type4; flag = L_CONNQUE; dis = !dis; break;
	      case 'r': addr = &LOG_type4; flag = L_NOCONNRECYC; break;
	      case 's':	addr = &LOG_type4; flag = L_CONNSCAT; dis = !dis; break;
	     }
	     break;
	    case 'h':
	     switch( arg[3] ){
	      case 'a': addr = &LOG_type4; flag = L_HTTPACCEPT;dis= !dis; break;
	     }
	     break;
	    case 'i':
	     switch( arg[3] ){
	      case 'd': addr = &LOG_type4; flag = L_DOSOCKDUP;dis = !dis; break;
	      case 'c': addr = &LOG_type4; flag = L_COPYCLADDR;dis= !dis; break;
	      case 'p': addr = &LOG_type4; flag = L_SOCKPAIRNM;dis= !dis; break;
	      case 's': addr = &LOG_type4; flag = L_NOSOCKINH;
		if( dis )
			LOG_type4 &= ~L_DOSOCKINH;
		else	LOG_type4 |=  L_DOSOCKINH;
		break;
	      case 't': addr = &LOG_type4; flag = L_WOSOCKINH; break;
	     }
	     break;
	    case 'k':
	     switch( arg[3] ){
	      case 0:	addr = &LOG_type3; flag = L_NOSERVKA|L_NOCLNTKA; break;
	      case 's': case 'v':
			addr = &LOG_type3; flag = L_NOSERVKA; break;
	      case 'c': case 't':
			addr = &LOG_type3; flag = L_NOCLNTKA; break;
	     }
	     break;
	    case 'l':	addr = &LOG_type3; flag = L_NOMMAPLOG; break;
	    case 'm':	addr = &LOG_type3; flag = L_NOMMAP; break;
	    case 'n':
	     switch( arg[3] ){
	      case 'h': addr = &LOG_type4; flag = L_DONTHT; dis = !dis; break;
	     }
	     break;
	    case 'r':
	     switch( arg[3] ){
	      case 'i': addr = &LOG_type4; flag = L_IMMREJECT; dis = !dis;break;
	      case 's': addr = &LOG_type4; flag = L_DOSRCREJECT;dis= !dis;break;
	     }
	     break;
	    case 's':
	     switch( arg[3] ){
	      case 't': addr = &LOG_type3; flag = L_NOSSLCHECK; break;
	     }
	     break;
	    case 't':
	     switch( arg[3] ){
	      case 's': addr = &LOG_type4; flag = L_THFORKSYNC; dis= !dis;break;
	      case 'w': addr = &LOG_type4; flag = L_TSWATCHER; dis= !dis;break;
	       default: addr = &LOG_type2; flag = L_NOTHREAD; break;
	     }
	     break;
	    case 'u':	addr = &LOG_type3; flag = L_NOUDPLOG; break;
	    case 'z':	addr = &LOG_type3; flag = L_NOGZIP; break;
	    case 'f':	addr = &LOG_type3; flag = L_FCLOSEQ; dis = !dis; break;
	    case 'w':   addr = &LOG_type3; flag = L_NOWIN; break;
	}
	if( addr != 0 && flag != 0 ){
		if( dis ){
			*addr |= flag;
		}else{
			*addr &= ~flag;
		}
	}
}
void setNumProcThread(PCStr(spec)){
	int nproc = 0;
	int nthread = 0;

	sscanf(spec,"%d+%d",&nproc,&nthread);
	if( nproc == 1 ){
		LOG_type3 |= L_SINGLEP;
		NUM_THSV = 1;
		if( 1 <= nthread ){
			NUM_THSV = nthread + 1;
			LOG_type3 |= L_MULTIST;
		}
	}else{
		LOG_type4 |= L_FXNUMSERV;
		NUM_FNSV = nproc;
	}
}

void setWinClassTitleStyle(PCStr(wclass),PCStr(wtitle),PCStr(wstyle));
int setDebugX(Connection *XConn,PCStr(arg),int force){
	const char *as;
	const char *val = &arg[2];
	int lev;
	LogControl olc;

	if( arg[0] != '-' )
		return 0;

	olc = *logControl;
	if( !force && lLOGSHARED() ){
	}else
	switch( arg[1] ){
	    case 'B':
		LOG_bugs |= (1 << atoi(&arg[2])-1);
		break;
	    case 'D':
		featuresED(arg);
		break;
	    case 'E': /* enable optional features */
		featuresED(arg);
		break;
	    case 'R':
		RAND_TRACE = 1;
		LOG_type1 |= L_RAND_TRACE;
		break;
	    case 'L':
		LOG_type_got = 1;
		if( val[0] == '0' ){
			sscanf(val,"0x%x",&LOG_type1);
		}else
		if( val[0] == '2' ){
			sscanf(val,"20x%x",&LOG_type2);
		}else
		if( val[0] == '3' ){
			sscanf(val,"30x%x/%x",&LOG_type3,&LOG_type4);
		}
		break;
	    case 'p':
		PEEK_CLIENT_REQUEST = 1;
		break;
	    case 't':
		LOG_type |= L_TTY;
		break;
	    case 'l':
		switch( arg[2] ){ 
		    case 's':
			LOG_type2 |= L_LOCKSHARED;
			lock_ext = 0;
			break;
		    default:
			LOG_type1 |= L_LOCK;
			break;
		}
		break;
	    case 'x':
		if( arg[2] == 's' )
			LOG_type1 |= L_FORK;
		else
		if( arg[2] == 'x' )
			LOG_type2 |= L_SEXEC;
		else
		if( arg[2] == 'f' )
			LOG_type4 |= L_EXECFILTER;
		else	LOG_type1 |= L_EXEC;
		break;

	    case 'w':
		if( arg[2] == 0 )
			LOG_type1 |= 1;
		else
		if( arg[2] == 'c' ){
			setWinClassTitleStyle(arg+3,0,0);
		}else
		if( arg[2] == 'i' || arg[2] == 'm' || arg[2] == 'n' ){
			setWinClassTitleStyle(0,0,arg+2);
		}else
		if( arg[2] == 't' ){
			setWinClassTitleStyle(0,arg+3,0);
		}else
		if( arg[2] == 'H' ){
			PollIn_HUP(0);
			fprintf(stderr,"POLLHUP disabled\n");
		}else
		if( '0' <= arg[2] && arg[2] <= '9' )
			LOG_type1 = (LOG_type1 & ~0xF) | (arg[2]-'0');
		break;
	    case 'n':
		setNumProcThread(arg+2);
		break;
	    case 'd':
		switch( arg[2] ){
		    case '0': LOG_type3 |= L_CURRENT; return 1;
		    case '1': case '2': case '3': case '4':
		    case '5': case '6': case '7': case '8': case '9':
			setNumProcThread(arg+2);
			return 1;
		    case 'c':
			if( arg[3] != '0' )
				LOG_type3 |= L_CONNECT;
			return 1;
		    case 'e':	LOG_type3 |= L_ENVIRON; return 1;
		    case 'g':	LOG_type3 |= L_THREADSIG; return 1;
		    case 'm':
			if( arg[3] ){
				LOG_type3 |= (L_MALLOC & atoi(&arg[3]));
			}else	LOG_type3 |= (L_MALLOC & 1);
			return 1;
		    case 'p':
			LOG_type4 |= L_PROCLOG;
			return 1;
		    case 'w':
			switch( arg[3] ){
			    case 's':
				LOG_type3 |= L_WINSOCK;
				break;
			}
			break;
		    case 'x': LOG_type3 |= L_TRANSMIT; return 1;
		    case 'z': LOG_type3 |= L_ZLIB; return 1;
		    case 'Z':
			if( arg[3] == 0 )
			      LOG_type3 |= L_NOGZIP;
			return 1;

		    case 'f': LOG_type1 |= L_FILETRACE; break;
		    case 'h': LOG_type1 |= L_HOSTMATCH; break;
		    case 's': LOG_type1 |= L_SOCKET; break;
		    case 't': LOG_type1 |= L_THREAD; break;
		    case 'M': LOG_type1 |= L_MOUNT; break;
		    case 'B': LOG_type2 |= L_COUNTER; break;
		    case 'C': LOG_type2 |= L_CHARSET; break;
		    case 'D': LOG_type2 |= L_DEBUGMSG; break;
		    case 'G': LOG_type2 |= L_GATEWAY; break;
		    case 'H': LOG_type2 |= L_HTMLGEN;
			if( arg[3] == '2' )
			      LOG_type2 |= L_HTMLGENV;
			break;
		    case 'L': LOG_type2 |= L_DEBUGLOCK; break;
		    case 'O': LOG_type2 |= L_FILEOPEN; break;
		    case 'P': LOG_type2 |= L_PATHFIND; break;
		    case 'S': LOG_type2 |= L_SECRET; break;
		    case 'T': LOG_type2 |= L_TLS; break;
		    case 'U': LOG_type2 |= L_URLFIND; break;
		    case 'W': LOG_type2 |= L_NO_WSOCKWA; break;
		    case 'F': LOG_type2 |= L_EMU_NOFORK; break;
		    case 'V': LOG_type2 |= L_NO_VSNPRINTF; break;
		    case 'A': LOG_type2 |= L_ACCESSCTL; break;
		    default:  LOG_type1 |= L_ARGDUMP;
			break;
		}
		break;

	    case 'v':
		if( arg[2] == 0 ){
			LOG_type1 |= L_FG | L_TTY;
		}else
		for( as = arg+2; *as; as++ ){
		    switch( *as ){
			case 'L': LOG_type3 |= L_LOGCTRL; break;
			case 'M': LOG_type3 |= L_MEMUSAGE; break;
			case 'F': LOG_type2 |= L_FILEDESC; break;
			case 'l': LOG_type2 |= L_DYLIB; break;
			case 'P': LOG_type2 |= L_POLL; break;
			case 'T': as += strlen(as)-1; break;
			case 'W': LOG_type2 |= L_SPAWNLOG; break;
			case 'S': LOG_type2 |= L_NOPROTOLOG; break;
			case 's': LOG_type1 |= L_SILENT; break;
			case 't': LOG_type1 |= L_TERSE; break;
			case 'u': /* usual */
				LOG_type1 &= ~(L_SILENT|L_TERSE|L_VERB);
				LOG_VERBOSE = 0;
				break;
			case 'v': LOG_type1 |= L_FG | L_TTY | L_VERB; break;
			case 'c': LOG_type1 |= L_CONSOLE; break;
			case 'd': LOG_type1 |= L_VERB; break;
			case 'a': LOG_type1 |= L_VERBABORT; break;
			case 'p': setupPeeping(XConn,as+1);
				as += strlen(as)-1; break;
			case 'Q': break; /* tmp. QUIET on loading self */
			case 'q': LOG_type4 |= L_QUIET; break;
			case 'r': LOG_type4 &= ~L_QUIET; break;
			case 'm': LOG_type1 |= L_MEMPUSH; break;
			case 'z': LOG_type3 |= L_ZLIB; break;
			case '2':
			case '3':
			case '4':
				lev = *as - '0';
				LOG_type1 = LOG_type1 & ~L_LEVEL | lev;
				break;
		    }
		}
		break;
	}

	switch( arg[1] ){
	    case 'v':
		if( arg[2] == 0 ){
		}else
		for( as = arg+2; *as; as++ ){
		    switch( *as ){
			case 'T': setLogTimeFmt(as+1);
				as += strlen(as)-1; break;
		    }
		}
		break;
	    case 'L':
		if( val[0] == '0' ){
		}else{
			setLogTimeFmtL(LOG_type2&L_TIMEFMT);
		}
		break;
	    case 'd':
		switch( arg[2] ){
		    case 'R': RES_debug(arg+3); break;
		}
		break;
	}

	if( lLOGCTRL() ){
		dumpLC(stderr,"OLD",&olc);
		dumpLC(stderr,"NEW",logControl);
	}
	return 0;
}
int setDebugForce(PCStr(arg)){
	return setDebugX(0,arg,1);
}
int setDebug(PCStr(arg)){
	return setDebugX(0,arg,0);
}

/* ])} */


#define DEF_NAMECONN	0x00010000 /* subst. name with Connection info. */
#define DEF_DATACONN	0x00020000 /* subst. data Connection info. */
#define DEF_DATAURL	0x00040000 /* subst. URL */

typedef struct {
	int dd_flags;
	const char *dd_name;
	const char *dd_data;
} DefData;
static DefData **defData;
#define NDGDEF 64
void scan_DGDEF(Connection *Conn,PCStr(defdata)){
	DefData *dd;
	int di;
	IStr(nametype,256);
	IStr(name,256);
	const char *data;
	const char *flags;

	data = wordScanY(defdata,nametype,"^:");
	if( *data == ':' )
		data++;
	flags = wordScanY(nametype,name,"^,");
	InitLog("DGDEF=%s[%s]:%s\n",name,flags,data);
	if( *flags == ',' )
		flags++;
	if( defData == 0 ){
		defData = (DefData**)malloc(NDGDEF*sizeof(DefData*));
		bzero(defData,sizeof(defData));
	}
	for( di = 0; di < NDGDEF; di++ ){
		dd = defData[di];
		if( dd == 0 ){
			dd = (DefData*)malloc(sizeof(DefData));
			bzero(dd,sizeof(DefData));
			defData[di] = dd;
			break;
		}
		if( streq(dd->dd_name,name) ){
			break;
		}
	}
	if( NDGDEF <= di ){
		return;
	}
	if( strchr(name,'%') )       dd->dd_flags |= DEF_NAMECONN;
	if( isinList(flags,"conn") ) dd->dd_flags |= DEF_DATACONN;
	if( isinList(flags,"url")  ) dd->dd_flags |= DEF_DATAURL;
	if( isinList(flags,"ei")   ) dd->dd_flags |= DGD_EVAL_ONINIT;
	if( isinList(flags,"si")   ) dd->dd_flags |= DGD_SUBST_ONINIT;
	dd->dd_name = (char*)stralloc(name);
	dd->dd_data = (char*)stralloc(data);
}
int evalDGDEF(Connection *Conn,PCStr(nametype),PVStr(data),int dz,int opts){
	DefData *dd;
	int di;
	IStr(xname,128);

	if( defData == 0 ){
		return 0;
	}
	for( di = 0; di < NDGDEF; di++ ){
		dd = defData[di];
		if( dd == 0 ){
			return 0;
		}
		if( opts & DGD_EVAL_ONINIT ){
		}
		if( dd->dd_flags & DEF_NAMECONN ){
			strfConnX(Conn,nametype,AVStr(xname),sizeof(xname));
		}else	strcpy(xname,nametype);
		if( streq(dd->dd_name,xname) ){
			if( dd->dd_flags & DEF_DATACONN )
				strfConnX(Conn,dd->dd_data,BVStr(data),dz);
			else	strcpy(data,dd->dd_data);
			return 1;
		}
	}
	return 0;
}
char *substDGDEF(Connection *Conn,PCStr(pat),PVStr(data),int dz,int opts,int encoding){
	const char *pp;
	const char *ep;
	int pc;
	refQStr(dp,data);
	IStr(nametype,256);
	refQStr(np,nametype);
	int subst = 0;

	if( defData == 0 ){
		return (char*)pat;
	}
	for( pp = pat; pc = *pp; pp++ ){
	  if( pp[0] == '_' && pp[1] == '{' ){
	    np = nametype;
	    for( ep = pp+2; *ep; ep++ ){
		if( ep[0] == '}' && ep[1] == '_' ){
			setVStrPtrInc(np,0);
			if( evalDGDEF(Conn,nametype,AVStr(dp),dz,opts) ){
				if( encoding & DGD_ESC_QUOTE ){
					strsubst(AVStr(dp),"\\","\\\\");
					strsubst(AVStr(dp),"\"","\\\"");
				}
				pp = ep+1;
				dp += strlen(dp);
				subst++;
				goto NEXTCH;
			}
		}
		setVStrPtrInc(np,*ep);
	    }
	  }
	  setVStrPtrInc(dp,pc);
	NEXTCH:;
	}
	if( subst ){
		setVStrPtrInc(dp,0);
		return (char*)data;
	}else{
		return (char*)pat;
	}
}
