How do I start a terminal instance from a compiled rust executable? - rust

I am making a small-scale project which reads from a file of 101 items, creates a vector of strings, and then randomly accesses one of the items and prints it to the standard output. The program works exactly as intended when run from the terminal, whether through cargo run
or by running the executable from the terminal with ./executable_name. The problem is, if I double click on the executable without a terminal open there is nowhere for the information to be printed and the program is essentially useless. I know how to check if a terminal is open using
if atty::is(Stream::Stdout) {
println!("Already in terminal");
} else {
// this is where I get confused
}
but from there I don't know where to go. I have experimented with things like Command::new("sh"); but am struggling with the documentation. Eventually, the idea is that I can compile this on my partners Mac without losing its functionality as I am writing it on Linux, and create an easy to use application to run it on her machine.

Programs generally do not open their own terminal windows. The way you arrange for one to exist varies by platform:
On macOS, you actually don't have to do anything; the default behavior of double-clicking an executable is to open a terminal to run it in. (GUI applications have their executables inside of .app packages, so that this behavior does not apply to them.)
On Windows, whether a terminal is opened is a property of the executable, which you can set in Rust with the windows_subsystem attribute. However, the default value is console so you don't need to do anything. (I've heard it is also possible to open a console window after startup, but I am not a Windows developer and can't advise you on the proper system calls to do that.)
On Linux, you'd create a .desktop file that specifies Terminal=true, to ask the desktop environment to launch your program in a terminal, and double-click that file rather than the executable. Or, you could make your program launch a terminal emulator and instruct it to start your program again within itself, but how you do that will depend on what terminal emulator programs are installed.
The one thing you'll have to do for all these cases is add a “Press Enter to exit” prompt to your program. Otherwise, the terminal will close immediately after your program exits, and so your output won't be visible.
eprintln!("Press Enter to exit.");
std::io::stdin().read_line(&mut String::new()).unwrap();

Related

Linux - Open terminal for input/output

I'm coding a Rust app and since it's fairly small and there don't appear to be any stable UI frameworks, I've made it run in the console using println! and whatnot for input/output. However since this program is intended to be used by people directly after downloading from the internet (due to its use case), they're likely to just double click on it instead of navigating to their downloads directory in a terminal and running it from there.
This is a problem because on Linux, it runs in the background waiting for input and looks like it's not working. On Windows, Rust programs do open in CMD by default. (and in fact many of the search results for my question were about disabling this behavior - the exact opposite of what I want!).
So is it possible to somehow make my application open in the system's default terminal? My preferred way would be to somehow embed in the executable to open in terminal (similar to the -mconsole compiler flag on MinGW). Otherwise would it be possible to detect it's in the background and fork it into a terminal? If that's not possible then is it at least possible to detect that the app is not running in a terminal and throw up a message box telling the user to run in a terminal?
My app is cross-platform but I'm OK with writing code conditionally compiled on one OS.
One typical way would be to distribute a program.sh along with your executable. If .sh extension is bound to opening a terminal in their window manager of choice, it would open automatically. If not - it is enough of a hint for running it from the shell.
Without this file you could:
Detect if the program is already running inside a terminal can be done with isatty(). There's a crate for it.
If not, spawn the terminal app process (see process::Command) and relaunch the program with it by passing its path to the terminal command line options. As #Caesar mentioned there's a bunch of popular terminals that you might want to check for presence on Linux. If nothing is found, xterm could sometimes be a fallback.

starting program in new terminal window

I have a program that needs to start another program. On my mac I did this using system("open path"), but on linux that doesn't work. and using system(./path) is not what I want since than it overtakes the running program.
So is there any way to get the same behaviour as the mac 'open path' command on linux?
(linux noob btw:p)
If you're running the application in a GUI environment, this should be possible but the approach is different. You need to start a new terminal instance explicitly.
Determine the path to your terminal application. This depends on the linux distribution.
Next, check the documentation of that particular terminal application and find out how it can be started to run an application (your application) instead of a shell. This probably involves using some application-specific command line options. Test that in a terminal window, until you have a command line that gives you the desired result. Things could get a little tricky if your application needs command line arguments as well. Use the -- option where necessary.
Then, all you need to do is run that command line from your "parent" application. I would advise however to not use system(). The exec... family functions (using fork and wait) provide better control.

addind FILE_SHARE_READ mode with cygwin

I did a very simple program in C for linux a few months ago to read data from a socket and write it to disk. Now I want to run it on Windows, so I installed cygwin and everything worked fine.
The problem appears in windows when my program is writing the data to a file and, at the same time, I try to open that file with another tool. It complains and doesn't open the file because it is opened by other process.
After googleing, I have read that to avoid that, in windows, you have to create the file with SHARE_FILE_READ and SHARE_FILE_WRITE flags, but the problem is that my program is written in C for linux and I just use a standard open syscall..
Is there any way to tell cygwin to add that shared modes to the file that my program is opening?
The issue is that both processes which open the file must do so with compatible sharing modes in order to succeed. Cygwin is opening the file with the correct sharing mode, but the other program is not.
For all files which are not special device files for tape drives, Cygwin opens them by calling NtCreateFile with a sharing mode of FILE_SHARE_VALID_FLAGS (equivalent to FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE)—see the implementation of fhandler_base::open() in fhandler.cc, which is what fopen(), open() etc. all use under the hood.
You need to convince your other program to open the file with the correct sharing mode; if it uses a sharing mode of 0 (no sharing), then it doesn't matter how Cygwin opens the file—the program will always get a sharing violation in that case.

I've downloaded an .exe file but it closes quickly as it opens

I am trying to open a downloaded .exe file but it closes as soon as it opens. Is there any possible way so that I can open it for a longer duration to read the content.
It's probably a console application rather than a GUI application. Use the command prompt to run the .exe.
Do the following...
Hold down your Windows key on your keyboard and then tap "R".
This will bring up the Run dialog. Type in "cmd" (without the quotes). Hit enter.
(this will work in all Windows versions - browsing the start menu/screen differs in each version)
If you saved the file to c:\downloads and it's called myFile.exe, type
C:
cd C:\Downloads
myFile.exe
Some of the steps are a bit redundant - if you know what you're doing in the command prompt then skip as needed (but then you probably wouldn't be posting this question). This will work even if you saved the file to D:\downloads.
Another example - if you saved the file to D:\folderA\Folder with a space\ and the file is called "my file with a space.exe" then type
D:
cd "D:\folderA\Folder with a space"
"my file with a space.exe"
If there is an issue (eg it's a 64-bit executable and you're on 32-bit Windows) then you may get a better error message at the command line.
There are so many reasons why the executable does not run. Here are some ways to check what is going wrong:
Is it your .exe? Do you known the "normal" behavior?
When you download it manually, it the result the same?
Do you download the .exe manually or via your application?
Do you see any problem in your Windows Event Viewer?
Is it the same result if you try to download the .exe via different browsers (IE, FF, ...)?
More details are welcome!
The nuget.exe file is not a console GUI application but rather a console package. Once you've downloaded it, you'll want to place it in a folder outside your Downloads folder. For example, C:\NuGet\nuget.exe - then set it as a PATH variable so that it's executable from anywhere.

Duplicate keyboard typing to another terminal

I have laptop-desktop setup at home and I have successfully cloned my Archlinux installation from one to another. However, I would like to avoid having to {install all new software, edit settings, update} twice, so I was wondering if it'd be possible to log over ssh from laptop to desktop, do something in terminal and have linux copy everything I type into second terminal with ssh logged in?
Thanks for ideas!
You could type the commands into one terminal then edit ~/.bash_history and save the commands into a script. Copy the script onto the machine with the second terminal and execute it. The advantage of this is now you have a script that saved your setup so you can reuse it whenever you need to.
You can use clusterssh, which duplicates your typed input across multiple systems. It is designed for situations in which the exact same tasks, such as software installation or configuration commands, are needed to be performed exactly the same on multiple systems. See http://sourceforge.net/projects/clusterssh/. Also, the KDE Konsole terminal has similar functionality.

Resources