Start another program then quit - process

From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
My current program:
use std::process::Command;
pub fn execute(exe: &str, args: &[&str]) {
Command::new(exe)
.args(args)
.spawn()
.expect("failed to start external executable");
}
fn main() {
execute("/usr/bin/nvim", &["/home/dys/todo.txt"]);
}
This fails. nvim is launched as a child and is non-working as soon as the calling program stops.
How can I write execute so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system) ?

After further discussion, we identified the actual problem: The program you are launching is supposed to stay in the foreground, so it can read from the terminal (which background processes can't do on Unix).
There are two ways to achieve this. The first, and easiest, is to wait for the child process before the parent process exits:
use std::process::{Command, ExitStatus};
use std::io::Result;
pub fn execute(exe: &str, args: &[&str]) -> Result<ExitStatus> {
Command::new(exe).args(args).spawn()?.wait()
}
This ensures the processes (parent and child) stay in the foreground, since the shell is waiting for the parent process, so the child process can read from the terminal.
If for some reason you can't afford the parent process to linger on while the child process is running, you need platform-dependent code. On Unix, you can use some syscall from the exec() familiy to replace the image of the parent process with the image of the child process:
use std::process::Command;
use std::os::unix::process::CommandExt;
use std::io::Error;
pub fn execute(exe: &str, args: &[&str]) -> Error {
Command::new(exe).args(args).exec()
}
The function only returns if there is an error. Otherwise, the process image is replaced by the new image. From the viewpoint of the shell, it's still the same process, so the shell will wait for the command you launched to finish.
The advantages of the second approach seem slim. It does not work on Windows, since Windows does not support exec() and friends. You will have one less process around while running the command, but the resource usage of that process should be small in practice – it does not use any CPU, and the memory pages can be swapped out if necessary.
Original Answer
From a program A written in rust, I want to start a program B, have A end, and have B normally run just like if it was manually launched from the same shell just after termination of A.
This is more or less what your code is already doing. There are a few differences to a process launched directly from the shell on Unix systems, though:
The new process will not be included in the shell's job list, so you can't use the shell's job control commands like bg and fg.
The new process will run in the background, and the shell will immediately show a prompt after the Rust programs exits.
This fails because nvim is launched as a child and is killed as soon as the calling program stops.
This is not true, neither for Unix nor for Windows.
How can I write execute so the caller program immediately stops and lets nvim (or another program) properly run (even without any windowing system)?
This should be exactly what your Rust code is doing (and what it does when run on my Linux machine). The code in your answer, on the other hand, does something else: It uses execv() to replace the Rust process with nvim. In effect, the process does not immediately stop, and the shell remaind blocked until nvim exits.

Here's a working solution on linux, using a wrapping ot the execv function:
use nix::unistd;
use std::ffi::CString;
pub fn executev(args: &[&str]) {
let mut args: Vec<CString> = args.iter()
.map(|t| CString::new(*t).expect("not a proper CString"))
.collect();
unistd::execv(
&args[0],
&args,
).expect("failed");
}
fn main() {
executev(&["/usr/bin/nvim", "/home/dys/todo.txt"]);
}
Note: This does start another program and quit but be wary that replacing the current process implies you properly closed open resources. If you can accept having your program kept alive, you probably want to wait as suggested by Sven Marnach.

Related

Execute Unidata Process from the shell command lines?

Is it possible to execute the Unidata process from the Unix Command line??
If it's possible, can anyone please let me know how to??
I just want to add some Unidata Processes into the shell script and run it from the Unix
Cron job.
Unidata Process
Unix Command line
Yes! There are several approaches, depending on how your application is setup.
Just pipe the input to the udt process and let 'er rip
$cd /path/to/account
$echo "COUNT VOC" | udt
This will run synchronously, and you may have to also respond to any prompts your application puts up, unless it is checking to see if the session is connected to a tty. Check the LOGIN paragraph in VOC to see what runs at startup.
Same, but run async as a phantom
$cd /path/to/account
$udt PHANTOM COUNT VOC
This will return immediately, the commands will run in the background. Have to check the COMO/PH file for the output from the command. It's common for applications to skip or have a cut down startup process when run as a phantom (check for #USERTYPE)
If none of the above work because of the way your application is written, use something like expect to force the issue.
spawn udt
expect "ogin:"
send "rubbleb\r"
etc.
https://en.wikipedia.org/wiki/Expect for more info on expect

Start a Spring-Shell based application not interactive

Is it possible to start a specific command of a Spring-Shell app and then return/exit the shell after the command is finished? Further is it possible to expose the exit code (System.exit) of the app to the operating system shell?
For my purpose i will take advantage of the plugin mechanism and the CLI-Annotations of Spring-Shell. But in general there is no human interaction with the app, instead a job scheduler (UC4) will start the app and check the exit code to generate an email in case of an exit code not equal to 0. On the other hand for manual tests by our customer, there is also the need of tab completion, usage help etc.
This behavior is already built-in (although we considered removing it, or at least make it optional). I see now that it is useful :)
Simply invoke the shell with your (sole) command and the shell will spin up, execute the command, and quit. Also, the return code of the shell already indicates whether there was an error or not (tried with an inexistant command for example). Of course, if your custom commands do not properly indicate an error (i.e. print an error message but perform a normal return) this will not work. You should throw an exception instead.
The behavior is back.
Run spring-shell with #my-script, like so:
java -jar my-app.jar #my-script
Where my-script is a file with your commands:
my-command1 arg1 arg2
my-command2 arg1 arg2

FORTRAN self-launching MPI program

Is there any way to call mprirun inside FORTRAN program? I'm working on public linux cluster via ssh and the main idea is to automatically enqueue program after its execution is over.
I tried to write something like this at the end of the program:
CALL system('mpirun -np 16 -maxtime 100 TestNP')
But recieved this error:
sh: mpirun: command not found
Any ideas ?
The problem is the missing path prefix, so specifying an absolute path for mpirun should help. However there are several problems with your approach:
If every MPI process executes it, you would have too many instances running, so only one of the nodes (e.g. the master node) should execute it.
The original program won't be finished, until the one called via the system() call did not finish. So, if your queue is wall-clock limited, you don't gain anything at all.
Typically, tasks like this are done via shell-scripts. E.g. in Bash you would write something like:
while true; do
mpirun your_program
done
This would re-invoke mpirun continuously until not killed by you or the queuing system. (So be careful with it!)

Query regarding running background/foreground processes via c program and fork()

Ok, my task is to write a C program that would run a particular process in background or foreground depending on whether & is the last argument or not. On googling, I found out that to run a process in background all you have to do is skip the line 'wait(&status)!=pid' in the parent process. The child process will run in the background.
That brings me to a query about fork(). When I type fork(), a child process is created. Now, my question is - Is the control of the program, right after calling fork(), passed to the child process before the parent process ALWAYS? Is it possible that the control is passed to parent process first? Or do both the processes run in parallel?
If the processes run parallel, I can see how skipping the wait part might work but not if the processes run sequentially.
For example:-
pid=fork()
if(pid==0) execvp("ls",argv);
else if(pid>0) return pid;
If suppose, the child process runs first. "pid==0" evaluates to true, execvp is called, ls is overwritten over the child process. "ls" terminates, control transfers to parent process. Here the wait command is not there and ls terminates and only then we go back to the parent process. Background working does not happen.
If parent process runs first, it sees that pid>0, control is transferred to main function. Since the wait command is not there, child process is not run at all, not at least until the parent process terminates.
So, how does it actually work? A few of my concepts might be way off the mark. if they are, kindly correct me.
Thanks.
Both parent and child processes are treated equally by the scheduler. You must not assume any predefined execution order and program synchronization if you need it.

Run script on Fedora screen lock

I'm looking for a way to run a program when locking the screen in Fedora 15 (linux). Basically I want to start running a motion detection program when the screen locks, or I manually hit Ctrl+Alt+L, but I don't know what commands are being run or where to alias my own intermediate step in. I assume it's:
gnome-screensaver-command --lock
but am not sure how to go about this. Anybody know how, or a direction to start looking in?
Edit, since link was in a comment:
This is done with dbus-monitor and described here.
The dbus system advertises screen locking; monitor for ActiveChanged on org.gnome.ScreenSaver. (see http://people.gnome.org/~mccann/gnome-screensaver/docs/gnome-screensaver.html )
e.g. (word-wrapped for clarity)
signal sender=:1.68 -> dest=(null destination)
serial=53 path=/org/gnome/ScreenSaver;
interface=org.gnome.ScreenSaver; member=ActiveChanged
boolean true
Unfortunately, this will require writing more code than just a shell script, I'm afraid; although I'd be curious if you could ask dbus to call your program as a handler for that signal, somehow; otherwise, I suppose you'd just start a daemon process and listen for that signal to be broadcast…