Being able to daemonize is a common thing for applications to do. There should be something in Rust similar to the C daemon function: http://man7.org/linux/man-pages/man3/daemon.3.html
Hey Alex, I asked on the mailing list and IRC on how to do this, and I didn't get any responses, so I assumed it wasn't possible. Can you explain how I can achieve the same functionality as the C daemon
function in Rust?
You'll want to spawn a new process with the detached
option set to true, like so:
use std::io::Command;
use std::os;
fn main() {
let args = os::args();
if args.len() == 1 {
let child = Command::new(args.get(0).as_slice())
.arg("child")
.detached().spawn().unwrap();
println!("child: {}", child.id());
child.forget();
} else {
println!("I'm a daemon!");
}
}
This is all possible today, so I'm going to close this issue.
So if I understand correctly, if I run this code with no arguments, I should see the process ID of the daemon and the daemon should print "I'm a daemon"? Because I only see the child process ID printed.
I believe that is because the child has been detached so it did not inherit the same stdio file descriptors.
I also added a 60 second sleep call after the "I'm a daemon!" println
and ran pgrep
and ps -p
with the child process ID. It doesn't seem like the daemon is running.
Ah, that's because the stdout handle is closed so the call to println!
is failing the rust task (discoverable through strace
)
Since std::io::Command is now defunct would someone be able to post a working example using std::process similar to the one that @alexcrichton posted above?
use std::process::Command;
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
if args.len() == 2 {
if &args[1] == "start" {
let child = Command::new(&args[0])
.spawn().expect("Child process failed to start.");
println!("child pid: {}", child.id());
// child.forget() No Child Left Behind
}
} else {
println!("This is an incredibly simple daemon!");
}
}
This works for me.
@somedude232 thanks
The code above is not an acceptable solution, it's a backdoor. If anyone has copied the code above into a suid program, privilege escalation is trivial, since the args array is set by the calling process and args[0] cannot be trusted. Even if that wasn't true, a race condition would still exist since the path args[0] names could be replaced before the Command is executed.
@Ofenhed do you have a safer alternative?
The correct way would be to demonize the actual running process. I haven't tried it, but running the unsafe libc functions fork
(and killing the parent) and setsid
may do the trick.
To slightly increase security with the examples above on systems with /proc
available, args[0]
could be replaced with "/proc/self/exe"
.
@alexcrichton Could we possibly reopen this thread (as it is not solved) or at least remove the backdoors as recommended solutions?
Most helpful comment
This works for me.