#pike __REAL_VERSION__ |
|
constant create_process = __builtin.create_process; |
|
#if constant(__builtin.TraceProcess) |
constant TraceProcess = __builtin.TraceProcess; |
#endif |
|
#if defined(__NT__) |
constant path_separator = ";"; |
#else |
constant path_separator = ":"; |
#endif |
|
#if constant(Stdio.__HAVE_SEND_FD__) |
protected Stdio.File forkd_pipe; |
protected create_process forkd_pid; |
|
|
|
|
|
class ForkdEncoder(Stdio.File remote_fd) |
{ |
int fd_counter; |
mixed nameof(mixed what) |
{ |
if (objectp(what)) { |
if (what->_fd) { |
remote_fd->send_fd(what->_fd); |
return fd_counter++; |
} |
} |
error("Unsupported argument for RemoteProcess.\n"); |
} |
} |
|
|
|
|
|
class ForkdDecoder(array(Stdio.Fd) fds) |
{ |
object objectof(mixed code) |
{ |
return fds[code]; |
} |
} |
|
|
protected int assert_forkd() |
{ |
if (!forkd_pid || !forkd_pid->kill(0)) { |
forkd_pipe = Stdio.File(); |
forkd_pid = spawn_pike(({ "-x", "forkd" }), |
([ |
"forkd":0, |
"uid":getuid(), |
"gid":getgid(), |
"noinitgroups":1, |
"fds":({ |
forkd_pipe->pipe(Stdio.PROP_BIDIRECTIONAL| |
Stdio.PROP_SEND_FD), |
}), |
])); |
if (forkd_pipe->read(1) != "\0") { |
|
return 0; |
} |
} |
return forkd_pid && forkd_pid->kill(0); |
} |
#endif |
|
protected int(0..1) forkd_default = 0; |
|
|
|
|
|
|
|
|
|
void set_forkd_default(int(0..1) mode) |
{ |
forkd_default = mode; |
} |
|
|
|
|
|
|
|
|
|
int(0..1) get_forkd_default() |
{ |
return forkd_default; |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Process |
{ |
|
inherit create_process; |
|
protected function(Process:void) read_cb; |
protected function(Process:void) timeout_cb; |
|
protected Stdio.File process_fd; |
|
protected Pike.Backend process_backend; |
|
protected mixed process_poll; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected void create( string|array(string) command_args, |
void|mapping(string:mixed) modifiers ) |
{ |
if( stringp( command_args ) ) { |
command_args = split_quoted_string( [string]command_args |
#ifdef __NT__ |
,1 |
#endif /* __NT__ */ |
); |
} |
|
mapping(string:mixed) new_modifiers = (modifiers || ([])) + ([]); |
|
if (new_modifiers->keep_signals) { |
|
m_delete(new_modifiers, "forkd"); |
} |
|
#if constant(Stdio.__HAVE_SEND_FD__) |
|
if (undefinedp(new_modifiers->forkd)) |
new_modifiers->forkd = forkd_default; |
if (new_modifiers->forkd && assert_forkd()) { |
process_fd = Stdio.File(); |
forkd_pipe-> |
send_fd(process_fd->pipe(Stdio.PROP_BIDIRECTIONAL|Stdio.PROP_SEND_FD)); |
while (forkd_pipe->write("\0") < 0) |
; |
|
m_delete(new_modifiers, "forkd"); |
__callback = m_delete(new_modifiers, "callback"); |
|
if (undefinedp(new_modifiers->uid)) { |
new_modifiers->uid = geteuid(); |
if (undefinedp(new_modifiers->gid)) { |
new_modifiers->gid = getegid(); |
} |
if (!new_modifiers->setgroups) { |
new_modifiers->setgroups = getgroups(); |
} |
} else if (new_modifiers->noinitgroups) { |
if (!new_modifiers->setgroups) { |
new_modifiers->setgroups = getgroups(); |
} |
} |
m_delete(new_modifiers, "noinitgroups"); |
|
if (!new_modifiers->env) { |
new_modifiers->env = getenv(); |
} |
|
if (new_modifiers->cwd) { |
new_modifiers->cwd = combine_path(getcwd(), new_modifiers->cwd); |
} else { |
new_modifiers->cwd = getcwd(); |
} |
|
if (!new_modifiers->stdin) new_modifiers->stdin = Stdio.stdin; |
if (!new_modifiers->stdout) new_modifiers->stdout = Stdio.stdout; |
if (!new_modifiers->stderr) new_modifiers->stderr = Stdio.stderr; |
|
string data = encode_value(({ command_args, new_modifiers }), |
ForkdEncoder(process_fd)); |
data = sprintf("%4c%s", sizeof(data), data); |
|
if (process_fd->read(4) != "\0\0\0\0") { |
process_fd->close(); |
process_fd = UNDEFINED; |
error("Failed to create spawn request.\n"); |
} |
int bytes = process_fd->write(data); |
if (bytes != sizeof(data)) { |
int fd_errno = process_fd->errno(); |
process_fd->close(); |
process_fd = UNDEFINED; |
error("Failed to write spawn request (%d != %d, errno: %d, errmsg: %s).\n", |
bytes, sizeof(data), fd_errno, strerror(fd_errno) || "?"); |
} |
process_backend = Pike.SmallBackend(); |
process_backend->add_file(process_fd); |
process_fd->set_nonblocking(got_data, UNDEFINED, got_close); |
|
|
while (__status == -1) { |
process_backend(3600.0); |
} |
|
if (process_fd) { |
process_poll = call_out(do_poll_loop, 0.1); |
} |
} else |
#endif |
{ |
::create( [array(string)]command_args, new_modifiers ); |
} |
|
if (modifiers) { |
if(read_cb = modifiers->read_callback) |
call_out(watcher, 0.1); |
|
if( (timeout_cb = modifiers->timeout_callback) || |
modifiers->timeout ) |
call_out(killer, modifiers->timeout||15); |
} |
} |
|
#if constant(Stdio.__HAVE_SEND_FD__) |
protected void do_close() |
{ |
if (process_fd) { |
process_fd->set_blocking(); |
process_fd->close(); |
} |
process_fd = UNDEFINED; |
process_backend = UNDEFINED; |
remove_call_out(process_poll); |
} |
|
protected string recv_buf = ""; |
protected void got_data(mixed ignored, string data) |
{ |
recv_buf += data; |
while (sizeof(recv_buf) > 3) { |
while (has_prefix(recv_buf, "\0\0\0\0")) recv_buf = recv_buf[4..]; |
if (sizeof(recv_buf) < 5) return; |
int len = 0; |
sscanf(recv_buf, "%04c", len); |
if (sizeof(recv_buf) < len + 4) return; |
data = recv_buf[4..len+3]; |
recv_buf = recv_buf[len+4..]; |
[string tag, mixed packet] = decode_value(data); |
|
switch(tag) { |
case "ERROR": |
__result = 255; |
__status = 2; |
do_close(); |
error(packet); |
break; |
case "PID": |
__pid = packet; |
if (__status == -1) __status = 0; |
if (__callback) __callback(this); |
break; |
case "SIGNAL": |
__last_signal = packet; |
break; |
case "START": |
__status = 0; |
if (__callback) __callback(this); |
break; |
case "STOP": |
__status = 1; |
if (__callback) __callback(this); |
break; |
case "EXIT": |
__result = packet; |
__status = 2; |
do_close(); |
if (__callback) __callback(this); |
break; |
default: |
__result = 255; |
__status = 2; |
do_close(); |
error("Unsupported packet from forkd: %O\n", tag); |
break; |
} |
} |
} |
|
protected void got_close(mixed ignored) |
{ |
do_close(); |
if (__status == -1) { |
|
__result = 255; |
__status = 2; |
} |
} |
|
protected void do_poll(float t) |
{ |
mixed err = catch { |
process_backend && process_backend(t); |
return; |
}; |
|
if (arrayp(err) && sizeof(err) && |
stringp(err[0]) && has_prefix(err[0], "Backend already ")) { |
sleep(t); |
return; |
} |
throw(err); |
} |
|
protected void do_poll_loop() |
{ |
process_poll = UNDEFINED; |
if (!process_backend) return; |
do_poll(0.0); |
process_poll = call_out(do_poll_loop, 0.1); |
} |
|
int last_signal() |
{ |
do_poll(0.0); |
return ::last_signal(); |
} |
|
int(-1..2) status() |
{ |
do_poll(0.0); |
return ::status(); |
} |
|
int wait() |
{ |
if (process_backend) { |
float t = 0.0; |
do { |
do_poll(t); |
if (t < 1.0) t += 0.1; |
} while (__status <= 0); |
return __result; |
} |
return ::wait(); |
} |
#endif /* __HAVE_SEND_FD__ */ |
|
protected void _destruct() { |
remove_call_out(watcher); |
remove_call_out(killer); |
#if constant(Stdio.__HAVE_SEND_FD__) |
remove_call_out(process_poll); |
#endif |
} |
|
protected void watcher() { |
|
if(status()==0) |
call_out(watcher, 0.1); |
else { |
remove_call_out(killer); |
if(read_cb) read_cb(this); |
} |
} |
|
protected void killer() { |
remove_call_out(watcher); |
#if constant(kill) |
::kill(signum("SIGKILL")); |
#endif |
if(timeout_cb) timeout_cb(this); |
} |
} |
|
|
string locate_binary(array(string) path, string name) |
{ |
#ifdef __NT__ |
if( !has_suffix(lower_case(name), ".exe") ) |
name += ".exe"; |
#endif |
|
foreach(path, string dir) |
{ |
string fname = combine_path(dir, name); |
Stdio.Stat info = file_stat(fname); |
if (info && (info->mode & 0111)) |
return fname; |
} |
return 0; |
} |
|
protected array(string) runpike; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Process spawn_pike(array(string) argv, void|mapping(string:mixed) options, |
array(string)|void launcher) |
{ |
if (!runpike) { |
array(string) res = ({ |
master()->_pike_file_name, |
}); |
if (master()->_master_file_name) |
res+=({"-m"+master()->_master_file_name}); |
foreach (master()->pike_module_path;;string path) |
res+=({"-M" + path}); |
if(options && options->add_predefines) |
{ |
foreach (master()->predefines; string key; string value) |
if( stringp( value ) ) |
res+=({"-D" + key + "=" + value}); |
else if( intp( value ) ) |
res+=({"-D" + key }); |
} |
if(options && options->add_program_path) |
{ |
foreach (master()->pike_program_path;; string value) |
res+=({"-P" + value}); |
} |
if(options && options->add_include_path) |
{ |
foreach (master()->pike_include_path;; string value) |
res+=({"-I" + value}); |
} |
|
if (sizeof(res) && !has_value(res[0],"/") |
#ifdef __NT__ |
&& !has_value(res[0], "\\") |
#endif /* __NT__ */ |
) |
res[0] = search_path(res[0]); |
runpike = res; |
} |
if (!launcher) launcher = ({}); |
return Process(launcher + runpike + argv, options); |
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mapping run(string|array(string) cmd, void|mapping modifiers) |
{ |
string gotstdout="", gotstderr="", stdin_str; |
int exitcode; |
|
if(!modifiers) |
modifiers = ([]); |
|
if((modifiers->stdout && !callablep(modifiers->stdout)) |
|| (modifiers->stderr && !callablep(modifiers->stderr))) |
throw( ({ "Can not redirect stdout or stderr in Process.run, " |
"please use Process.Process instead.", backtrace() }) ); |
|
Stdio.File mystdout = Stdio.File(); |
Stdio.File mystderr = Stdio.File(); |
Stdio.File mystdin; |
|
object p; |
if(stringp(modifiers->stdin)) |
{ |
mystdin = Stdio.File(); |
stdin_str = modifiers->stdin; |
p = Process(cmd, modifiers + ([ |
"stdout":mystdout->pipe(), |
"stderr":mystderr->pipe(), |
"stdin":mystdin->pipe(Stdio.PROP_IPC|Stdio.PROP_REVERSE) |
])); |
} |
else |
p = Process(cmd, modifiers + ([ |
"stdout":mystdout->pipe(), |
"stderr":mystderr->pipe(), |
])); |
|
#if 0 //constant(Thread.Thread) |
|
|
array threads = ({ |
thread_create( lambda() { gotstdout = mystdout->read(); } ), |
thread_create( lambda() { gotstderr = mystderr->read(); } ) |
}); |
|
if (mystdin) { |
threads += ({ |
thread_create(lambda(Stdio.File f) { f->write(stdin_str); f->close(); }, mystdin ) |
}); |
mystdin = 0; |
} |
|
exitcode = p->wait(); |
threads->wait(); |
#else |
Pike.SmallBackend backend = Pike.SmallBackend(); |
|
mystdout->set_backend (backend); |
mystderr->set_backend (backend); |
|
mystdout->set_read_callback( lambda( mixed i, string data) { |
if (modifiers->stdout) modifiers->stdout(data); |
else gotstdout += data; |
} ); |
mystderr->set_read_callback( lambda( mixed i, string data) { |
if (modifiers->stderr) modifiers->stderr(data); |
else gotstderr += data; |
} ); |
mystdout->set_close_callback( lambda () { |
mystdout->set_read_callback(0); |
catch { mystdout->close(); }; |
mystdout = 0; |
}); |
mystderr->set_close_callback( lambda () { |
mystderr->set_read_callback(0); |
catch { mystderr->close(); }; |
mystderr = 0; |
}); |
|
#if constant(Shuffler) |
if (mystdin) { |
if (stdin_str != "") { |
Shuffler.Shuffler sfr = Shuffler.Shuffler(); |
sfr->set_backend (backend); |
Shuffler.Shuffle sf = sfr->shuffle( mystdin ); |
sf->add_source(stdin_str); |
sf->set_done_callback (lambda () { |
catch { mystdin->close(); }; |
mystdin = 0; |
}); |
sf->start(); |
} else { |
catch { mystdin->close(); }; |
mystdin = 0; |
} |
} |
#endif |
|
while( mystdout || mystderr || mystdin ) |
backend( 1.0 ); |
|
exitcode = p->wait(); |
#endif |
|
return ([ "stdout" : gotstdout, |
"stderr" : gotstderr, |
"exitcode": exitcode ]); |
} |
|
#if constant(exece) |
|
int exec(string file,string ... foo) |
{ |
if (sizeof(file)) { |
string path; |
|
if(has_value(file,"/")) |
return exece(combine_path(getcwd(),file),foo, |
[mapping(string:string)]getenv()); |
|
path=[string]getenv("PATH"); |
|
foreach(path ? path/":" : ({}) , path) |
if(file_stat(path=combine_path(path,file))) |
return exece(path, foo, [mapping(string:string)]getenv()); |
} |
return 69; |
} |
#endif |
|
protected string search_path_raw; |
protected array(string) search_path_entries=0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string search_path(string command) |
{ |
if (command=="" || command[0]=='/') return command; |
|
string path = getenv("PATH")||""; |
if ((path != search_path_raw) || !search_path_entries) |
{ |
string raw_path = path; |
#ifdef __NT__ |
path = replace(path, "\\", "/"); |
#endif |
array(string) e = path/path_separator - ({""}); |
|
multiset(string) filter=(<>); |
array(string) entries=({}); |
foreach (e,string s) |
{ |
string t; |
if (s[0]=='~') |
{ |
if (s[0..1]=="~/" && (t=System.get_home())) |
s=t+s[1..]; |
else |
{ |
|
} |
#ifdef __NT__ |
} else if (sizeof(s) && (s[0] == '"') && s[-1] == '"') { |
|
|
|
s = s[1..<1]; |
#endif /* __NT__ */ |
} |
if (!filter[s] ) |
{ |
entries += ({s}); |
filter[s]=1; |
} |
} |
|
search_path_entries = entries; |
search_path_raw = raw_path; |
} |
return locate_binary(search_path_entries, command); |
} |
|
|
string sh_quote(string s) |
{ |
return replace(s, |
({"\\", "'", "\"", " "}), |
({"\\\\", "\\'", "\\\"","\\ "})); |
} |
|
array(string) split_quoted_string(string s, int(0..1)|void nt_mode) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
|
sscanf(s,"%*[ \t\n\r]%s",s); |
|
|
|
s=replace(s, |
({"\"", "'", "\\", " ", "\t", "\n", "\r", "\0"}), |
({"\0\"","\0'","\0\\","\0 ","\0\t","\0\n", "\0\r", "\0\0"})); |
array(string) x=s/"\0"; |
array(string) ret = ({}); |
string last = x[0]; |
int always_keep_last; |
|
piece_loop: |
for(int e=1;e<sizeof(x);e++) |
{ |
string piece = x[e]; |
if (piece == "") { |
|
last += "\0" + x[++e]; |
continue; |
} |
switch(piece[0]) |
{ |
case '"': |
always_keep_last = 1; |
last+=piece[1..]; |
while (1) { |
if (++e == sizeof (x)) |
break piece_loop; |
if (has_prefix (piece = x[e], "\"")) |
break; |
if (piece == "") { |
last += "\0" + x[++e]; |
} |
else { |
if(piece == "\\" && sizeof (x) > e + 1 && has_prefix (x[e+1], "\"")) |
piece = x[++e]; |
last+=piece; |
} |
} |
last+=piece[1..]; |
break; |
|
case '\'': |
always_keep_last = 1; |
last+=piece[1..]; |
while (1) { |
if (++e == sizeof (x)) |
break piece_loop; |
if (has_prefix (piece = x[e], "'")) |
break; |
if (piece == "") { |
last += "\0" + x[++e]; |
} |
else |
last+=piece; |
} |
last+=piece[1..]; |
break; |
|
case '\\': |
if(sizeof(piece)>1) |
{ |
if (nt_mode) { |
|
|
last+=piece; |
} else { |
last+=piece[1..]; |
} |
}else if (sizeof (x) > e + 1) { |
|
last+=x[++e]; |
} |
break; |
|
case ' ': |
case '\t': |
case '\n': |
case '\r': |
while(sizeof(piece)==1) |
{ |
if(e+1 < sizeof(x)) |
{ |
if((<' ','\t','\n', '\r'>) [x[e+1][0]]) |
piece = x[++e]; |
else |
break; |
}else{ |
break piece_loop; |
} |
} |
if (sizeof (last) || always_keep_last) |
ret += ({last}); |
last = piece[1..]; |
break; |
} |
} |
if (sizeof (last) || always_keep_last) |
ret += ({last}); |
return ret; |
} |
|
__deprecated__ Process spawn(string command, |
void|Stdio.Stream stdin, |
void|Stdio.Stream stdout, |
void|Stdio.Stream stderr, |
|
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
mapping(string:mixed) data=(["env":getenv()]); |
if(stdin) data->stdin=stdin; |
if(stdout) data->stdout=stdout; |
if(stderr) data->stderr=stderr; |
#if defined(__NT__) |
|
|
if (sizeof(command) <= 1 || |
command[0] != '\"' || command[sizeof(command)-1] != '\"') |
command = "\"" + command + "\""; |
return Process(({ "cmd", "/c", command }),data); |
#else /* !__NT__ */ |
return Process(({ "/bin/sh", "-c", command }),data); |
#endif /* __NT__ */ |
} |
|
#pragma no_deprecation_warnings |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
variant __deprecated__ string popen(string s) { |
return fpopen(s)->read(); |
} |
|
variant __deprecated__ Stdio.FILE popen(string s, string mode) { |
return fpopen(s,mode); |
} |
|
protected __deprecated__ Stdio.FILE fpopen(string s, string|void mode) |
{ |
Stdio.FILE f = Stdio.FILE(); |
if (!f) error("Popen failed. (couldn't create file)\n"); |
|
Stdio.File p = f->pipe(); |
if(!p) error("Popen failed. (couldn't create pipe)\n"); |
|
if (mode == "w") |
spawn(s, p, 0, 0, ); |
else |
spawn(s, 0, p, 0, ); |
p->close(); |
destruct(p); |
|
return f; |
} |
|
__deprecated__ int system(string command, void|Stdio.Stream stdin, |
void|Stdio.Stream stdout, void|Stdio.Stream stderr) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
return spawn(command, stdin, stdout, stderr)->wait(); |
} |
|
#pragma deprecation_warnings |
|
#ifndef __NT__ |
#if constant(fork) |
constant fork = predef::fork; |
#endif |
|
#if constant(exece) |
constant exece = predef::exece; |
#endif |
|
#if constant(fork) && constant(exece) |
|
|
class Spawn |
{ |
object stdin; |
object stdout; |
object stderr; |
array(object) fd; |
|
object pid; |
|
private object low_spawn(array(Stdio.File) fdp, |
array(Stdio.File) fd_to_close, |
string cmd, void|array(string) args, |
void|mapping(string:string) env, |
string|void cwd) |
{ |
Stdio.File pie, pied; |
object pid; |
|
pie=Stdio.File(); |
pied=pie->pipe(); |
|
if(!(pid=fork())) |
{ |
mixed err=catch |
{ |
if(cwd && !cd(cwd)) |
{ |
error( "pike: cannot change cwd to %O: %s.\n", cwd, |
strerror(errno()) ); |
} |
|
if (sizeof(fdp)>0 && fdp[0]) fdp[0]->dup2(Stdio.File("stdin")); |
if (sizeof(fdp)>1 && fdp[1]) fdp[1]->dup2(Stdio.File("stdout")); |
if (sizeof(fdp)>2 && fdp[2]) fdp[2]->dup2(Stdio.File("stderr")); |
|
foreach (fd_to_close, Stdio.File f) |
if (objectp(f)) { f->close(); destruct(f); } |
pie->close(); |
destruct(pie); |
|
pied->set_close_on_exec(1); |
|
if (env) |
exece(cmd,args||({}),env); |
else |
exece(cmd,args||({})); |
|
error( "pike: failed to exece %O: %s.\n", cmd, |
strerror(errno()) ); |
}; |
|
pied->write(encode_value(err)); |
exit(1); |
} |
|
foreach (fdp,object f) if (objectp(f)) { f->close(); destruct(f); } |
|
pied->close(); |
destruct(pied); |
|
mixed err=pie->read(); |
if (err && err!="") throw(decode_value(err)); |
|
pie->close(); |
destruct(pie); |
|
return pid; |
} |
|
|
protected void create(string cmd, |
void|array(string) args, |
void|mapping(string:string) env, |
string|void cwd, |
void|array(object(Stdio.File)|void) ownpipes, |
void|array(object(Stdio.File)|void) fds_to_close) |
{ |
if (!ownpipes) |
{ |
stdin=Stdio.File(); |
stdout=Stdio.File(); |
stderr=Stdio.File(); |
fd=({stdin->pipe(),stdout->pipe(),stderr->pipe()}); |
fds_to_close=({stdin,stdout,stderr}); |
} |
else |
{ |
fd=ownpipes; |
if (sizeof(fd)>0) stdin=fd[0]; else stdin=0; |
if (sizeof(fd)>1) stdout=fd[1]; else stdout=0; |
if (sizeof(fd)>2) stderr=fd[2]; else stderr=0; |
} |
pid=low_spawn(fd,fds_to_close||({}),cmd,args,env,cwd); |
} |
|
#if constant(kill) |
|
int kill(int signal) |
{ |
return predef::kill(pid,signal); |
} |
#endif |
|
|
int wait() |
{ |
return pid->wait(); |
} |
|
|
|
|
} |
#endif |
#endif |
|
#if constant(fork) || constant(System.daemon) |
private int low_daemon(int nochdir, int noclose) |
{ |
#if constant(System.daemon) |
return System.daemon(nochdir, noclose); |
#else |
if (fork()) |
exit(0); |
|
#if constant(System.setsid) |
System.setsid(); |
#endif /* System.setsid */ |
|
if (!nochdir) |
cd("/"); |
|
Stdio.File fd; |
if (!noclose && (fd = Stdio.File("/dev/null", "rw"))) |
{ |
fd->dup2(Stdio.stdin); |
fd->dup2(Stdio.stdout); |
fd->dup2(Stdio.stderr); |
if (fd->query_fd() > 2) |
fd->close(); |
} |
return 0; |
#endif /* !System.daemon */ |
} |
|
void daemon(int nochdir, int noclose, |
void|mapping(string:string|Stdio.File) modifiers) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{ |
array(Stdio.File) opened = ({}); |
Stdio.File getfd(string|object f) |
{ |
if (stringp(f)) |
{ |
Stdio.File ret = Stdio.File(f, "crw"); |
opened += ({ ret }); |
return ret; |
} |
else if (objectp(f)) |
return f; |
else |
return 0; |
}; |
|
if (low_daemon(nochdir, noclose) == -1) |
error("Failed to daemonize: %s.\n", strerror(errno())); |
if (!modifiers) |
return; |
|
if (modifiers["cwd"]) |
cd(modifiers["cwd"]); |
|
if (modifiers["stdin"]) |
getfd(modifiers["stdin"])->dup2(Stdio.stdin); |
|
if (modifiers["stdout"]) |
getfd(modifiers["stdout"])->dup2(Stdio.stdout); |
|
if (modifiers["stderr"]) |
getfd(modifiers["stderr"])->dup2(Stdio.stderr); |
|
opened->close(); |
} |
#endif |
|
|