#!/usr/local/bin/pike |
|
|
inherit Stdio.Port; |
|
#if !constant(Stdio.PROP_IPC) |
#define NO_IPC |
#endif |
|
|
string combine_path(string s, string ... rest) |
{ |
for(int e=0;e<sizeof(rest);e++) |
{ |
if(sscanf(rest[e],"%*[a-zA-Z]:%*s")==2) |
{ |
s=rest[e]; |
}else{ |
s=predef::combine_path(s,rest[e]); |
} |
} |
return s; |
} |
|
|
#define BLOCK 65536 |
int cp(string from, string to) |
{ |
if(!Stdio.cp(from,to)) |
{ |
werror("Backup cp function in effect.\n"); |
|
string data; |
object tmp=Stdio.File(); |
if(!tmp->open(from,"r")) |
{ |
werror(sprintf("Open %s for reading failed.\n",from)); |
return 0; |
} |
function r=tmp->read; |
tmp=Stdio.File(); |
if(!tmp->open(to,"wct")) |
{ |
werror(sprintf("Open %s for writing failed.\n",to)); |
return 0; |
} |
function w=tmp->write; |
do |
{ |
data=r(BLOCK); |
if(!data) |
{ |
werror("Read failed.\n"); |
return 0; |
} |
if(w(data)!=strlen(data)) |
{ |
werror("Write failed.\n"); |
return 0; |
} |
}while(strlen(data) == BLOCK); |
} |
return 1; |
} |
|
void monitor(object(Stdio.File) io, object proc) |
{ |
proc->wait(); |
if(io) |
{ |
io->close("rw"); |
io->close(); |
destruct(io); |
} |
} |
|
string opt_path(string p1, string p2) |
{ |
return ( ( ((p1||"") + ";" + (p2||"")) / ";" ) - ({""}) ) * ";"; |
} |
|
Thread.Mutex outlock=Thread.Mutex(); |
|
void myproxy(object pi, object io, int channel) |
{ |
while(1) |
{ |
string s=pi->read(1000,1); |
if(!s || !strlen(s)) break; |
object key=outlock->lock(); |
io->write(sprintf("%c%3c%s",channel,strlen(s),s)); |
destruct(key); |
} |
} |
|
void handle_incoming_connection(object(Stdio.File) io) |
{ |
object p; |
mapping env=copy_value(getenv()); |
sscanf(io->read(4),"%4c",int args); |
string *cmd=allocate(args); |
for(int e=0;e<args;e++) |
{ |
sscanf(io->read(4),"%4c",int len); |
cmd[e]=io->read(len); |
} |
|
object pi=Stdio.File(); |
object pe=Stdio.File(); |
#ifdef NO_IPC |
object p2=pi->pipe(); |
object pe2=pe->pipe(); |
#else |
object p2=pi->pipe(Stdio.PROP_IPC); |
object pe2=pe->pipe(Stdio.PROP_IPC); |
#endif |
string dir=cmd[0]; |
cmd=cmd[1..]; |
|
while(sscanf(cmd[0],"%s=%s",string key, string val)) |
{ |
|
if(!env[key]) |
{ |
if(env[lower_case(key)]) |
key=lower_case(key); |
else if(env[upper_case(key)]) |
key=upper_case(key); |
else |
{ |
foreach(indices(env), string x) |
{ |
if(lower_case(x) == lower_case(key)) |
{ |
key=x; |
break; |
} |
} |
} |
} |
if(val[0]==';') |
{ |
env[key]=opt_path(env[key], val); |
} |
else if(val[-1]==';') |
{ |
env[key]=opt_path(val, env[key]); |
} |
else |
{ |
env[key]=val; |
} |
werror("%s = %s\n",key,env[key]); |
cmd=cmd[1..]; |
} |
|
write("Doing %s in %s\n",cmd*" ",dir); |
|
switch(lower_case(cmd[0])) |
{ |
case "mkdir": |
{ |
string dir=combine_path(combine_path(getcwd(),dir),cmd[1]); |
int ret; |
if(Stdio.file_size(dir)!=-2) |
ret=mkdir(dir); |
else |
ret=1; |
if(!ret) |
{ |
string x=sprintf("MKDIR %s failed, errno=%d\n",dir,errno()); |
io->write(sprintf("%4c%s",strlen(x),x)); |
} |
io->write(sprintf("%4c",0)); |
io->write(sprintf("%4c",!ret)); |
break; |
} |
|
case "copy": |
{ |
string from=combine_path(combine_path(getcwd(),dir),cmd[1]); |
string to=combine_path(combine_path(getcwd(),dir),cmd[2]); |
|
if(mixed stat=file_stat(to)) |
{ |
if(stat[1]==-2) |
{ |
to=combine_path(to,basename(cmd[1])); |
} |
} |
|
|
int ret=cp(from,to); |
if(!ret) |
{ |
string x=sprintf("Errno is %d\n" |
"CWD=%s\n" |
"from=%s\n" |
"to=%s\n" |
"dir=%s (%s)\n", |
errno(), |
getcwd(), |
from, |
to, |
dir, combine_path(getcwd(),dir)); |
io->write(sprintf("%4c%s",strlen(x),x)); |
} |
io->write(sprintf("%4c",0)); |
io->write(sprintf("%4c",!ret)); |
break; |
} |
case "getenv": |
{ |
string s; |
if(sizeof(cmd)<2) |
{ |
s=""; |
foreach(indices(env), string x) |
s+=sprintf("%s=%s\n",x,env[x]); |
}else{ |
s=(env[cmd[1]] || "")+"\n"; |
} |
io->write(sprintf("%4c%s",strlen(s),s)); |
io->write(sprintf("%4c",0)); |
io->write(sprintf("%4c",0)); |
break; |
} |
|
default: |
#ifdef WINE |
void my_proxy(Stdio.File from, Stdio.File to) |
{ |
while(string s=from->read(128,1)) |
if(to->write(s)!=strlen(s)) |
return; |
if(p) p->kill(9); |
} |
|
{ |
werror("Proxying.....\n"); |
object p3=Stdio.File(); |
#ifdef NO_IPC |
object p4=p3->pipe(); |
#else |
object p4=p3->pipe(Stdio.PROP_IPC); |
#endif |
thread_create(my_proxy,io,p4); |
io=p3; |
} |
#endif |
|
#if __VERSION__ >= 0.699999 |
write("Trapping OOB\n"); |
if(io->read_oob) |
{ |
thread_create(lambda() { |
while(1) |
{ |
string tmp=io->read_oob(1); |
if(!tmp || !sizeof(tmp)) return; |
werror("**Interrupt received, killing child.\n"); |
p->kill(9); |
} |
}); |
} |
#endif |
|
mixed err=catch { |
p=Process.create_process(cmd, |
([ |
#ifndef WINE |
"stdin":io, |
"stdout":p2, |
"stderr":pe2, |
#endif |
"cwd":dir, |
"env":env, |
])); |
}; |
destruct(p2); |
destruct(pe2); |
if(!err) |
{ |
#ifdef NO_IPC |
thread_create(monitor,p2,p); |
#endif |
|
object proxythread; |
if(env->__handles_stderr) |
{ |
proxythread=thread_create(myproxy,pe,io,2); |
myproxy(pi,io,1); |
}else{ |
proxythread=thread_create(myproxy,pe,io,0); |
myproxy(pi,io,0); |
} |
proxythread->wait(); |
|
io->write(sprintf("%4c",0)); |
int code; |
if (catch { code = p->wait(); }) { |
|
io->write(sprintf("%4c", -1)); |
} else { |
io->write(sprintf("%4c", code)); |
} |
}else{ |
werror("dir=%s\n",dir); |
werror(master()->describe_backtrace(err)); |
destruct(p2); |
io->write(sprintf("%4c",0)); |
io->write(sprintf("%4c",69)); |
} |
} |
#ifdef WINE |
io->close("rw"); |
#else |
io->close("w"); |
#endif |
destruct(io); |
} |
|
void handle_connections(string *hosts) |
{ |
while(1) |
{ |
if(object io=accept()) |
{ |
int ok=0; |
sscanf(io->query_address(),"%s ",string ip); |
foreach(hosts, string host) ok+=glob(host, ip); |
if(!ok) |
{ |
werror("Connection from %s denied!!\n",ip); |
destruct(io); |
continue; |
} |
thread_create(handle_incoming_connection,io); |
}else{ |
werror("Accept failed "+errno()+"\n"); |
} |
} |
} |
|
int main(int argc, string *argv) |
{ |
#ifdef WINE |
werror("Running in WINE mode.\n"); |
#endif |
if(argc<2) |
{ |
werror("Usage: sprshd <port> <hosts to accept connections from>\n"); |
exit(1); |
} |
if(!bind((int)argv[1])) |
{ |
werror("Failed to bind port.\n"); |
exit(1); |
} |
|
string *hosts=({}); |
for(int e=2;e<sizeof(argv);e++) |
{ |
if(sscanf(argv[e],"%*d.%*d")==2) |
{ |
hosts+=({argv[e]}); |
continue; |
} |
mixed tmp=gethostbyname(argv[e]); |
if(!tmp) |
{ |
werror("Gethostbyname("+argv[e]+") failed.\n"); |
exit(1); |
} |
hosts+=tmp[1]; |
} |
|
write("Ready ("+version()+").\n"); |
|
#ifdef WINE |
thread_create(handle_connections,hosts); |
werror("main returning...\n"); |
return -1; |
#else |
handle_connections(hosts); |
return 0; |
#endif |
} |
|
|