Starting the default terminal on Linux - c++

Tell me, please, is it possible to call the Linux Terminal, which is installed by default, in some way (method)?
Now, I run the process in the xfce4-terminal terminal, specifying this terminal and the arguments to it:
QProcess up;
QString cArg;
cArg="/tmp/cp.py -y " + ye;
up.start("xfce4-terminal", QStringList()<< "--geometry=120x40" << "--command" << "python3 "+ cArg << "-H");
up.waitForFinished();
up.close();

No, there is no general way in the Linux kernel to find out which (or whether a) terminal emulator is installed on the system by default.
Although the (fairly ubiquitous) freedesktop.org specifications describe how to associate MIME type with a default application, there isn't a specification for default application without an associated file to be opened as far as I can tell. Each desktop environment that has a concept of "default terminal emulator" has their own way of configuring it.
Debian has has "update-alternatives" system that allows configuration of "default" applications based on aliases, and it has a package that creates an alias x-terminal-emulator that can be used to configure the default terminal emulator.
Here is a reasonable strategy for choosing the command in your program:
Let the user configure the command. Use this with highest priority if configured.
Use XDG_CURRENT_DESKTOP environment variable, and implement logic for each desktop environment to read their configuration to find out the configured default emulator. Use this as the second highest priority when available.
Collect a list of commonly used terminal emulators. Put aliases such as x-terminal-emulator with higher priority in the list.
With this list starting with user configuration and ending with your hard-coded list, check each command and see if it's executable and pick the first one that is. In case user has configured the command, and it isn't executable, I recommend an optional error message.

You can use i3's sensible-terminal script.
https://github.com/i3/i3/blob/next/i3-sensible-terminal
While it has been made for i3, if you read the source you'll see it's very simple and doesn't rely on it, so feel free to use this within whatever desktop environment you want.
Though if you don't use i3 you may want to remove the last line (which isn't that important as you are unlikely to have no terminal installed at all).
Explanations
It proceeds by getting, in this order:
A terminal you may have defined in the non-standard $TERMINAL environment variable
x-terminal-emulator which is a similar utility for Debian only
A list of hardcoded terminals, namely mate-terminal gnome-terminal terminator xfce4-terminal urxvt rxvt termit Eterm aterm uxterm xterm roxterm termite lxterminal terminology st qterminal lilyterm tilix terminix konsole kitty guake tilda alacritty hyper

Related

C++ - How to detect I am running without a terminal

In C/C++ how can my programs determine if there is a desktop (system or remote) or not?
My project has three separate programs running (now) in separate gnome-terminals. It is launched by the last line of .profile, so it starts whether I am at the system desktop (gnome) or remotely connecting by VPN/telnet or VPN/remote-desktop. My machine is 250 miles away at a test site, so I frequently login remotely to make changes and have to restart the program.
I'd like my program to be able to detect that it is launched from a desktop environment or from a telnet session. Preferably, I want them to continue running after the remote connection is broken.
Obviously, I need to make my programs into daemons so they will persist after I close the connection. But if I start them in a terminal on a desktop environment, where I can actually have three terminals open, I'd like to watch their progress messages. And if I disconnect the remote desktop, I'd like the daemons to detect this and turn off printing (to the now killed terms) but keep on running in normal (silent) daemon mode. Best of all, the programs could recheck for a desktop occasionally and resume printing by opening new terminals.
Is this possible? Any coding suggestions?
Thanks in advance.
You can use the isatty function. Detect if stdin is a terminal or pipe?
#include <stdio.h>
#include <io.h>
//...
if (isatty(fileno(stdin)))
printf( "stdin is a terminaln" );
else
printf( "stdin is a file or a pipen");
You can find more information at http://www.chemie.fu-berlin.de/chemnet/use/info/libc/libc_12.html
Some more code: http://pastebin.com/S3Lr9tik
The traditional solution for this problem is an option in the command
line. Such programs will typically demonize themselves unless given a
special debug option telling them not to.
Another solution would be to use a shell script to start the program as
a demon, via the nohup command (and redirecting standard input and
output to /dev/null).
As for determining whether your managing terminal is local or not, it
could be difficult; both X and telnet use virtual terminals, so if
you're running under X, you may not be able to distinguish between a
telnet session and a local xterm window. Still, it might be worth
trying... Under Linux, /proc/<procid>/fd/0 is a symbolic link to the
device connected to standard in (fd 0): using something like readlink,
you should be able to determine the actual name. Or fstat will give
you the major and minor numbers of the device. Given these, you might
be able to determine which is which. If your local terminal is not
under X, but a real terminal, it will definitely have a different minor
number than a pseudo-terminal. For xterms, it's possible that the minor
numbers of the pseudo-terminals fall in different ranges, or even that
there are distinct sets of pseudo-terminals for remote links and for X;
you'll probably have to experiment some, and there might be no working
solution. (For starters, to tty at each terminal, and see what it
says. I don't have local access to a Linux machine to check, but I seem
to remember that on Solaris, X terminals had names like /dev/ttyxx; my
remote terminals on Linux here are /dev/pts/xx. (Where xx is a
number in each case.)

Are system() calls evil?

I am designing an C++ app that, among other things, executes a few scripts every now and then. The app should be efficient and preferably platform independent.
The issue is, however: is there a reason one shouldn't use system() call for launching scripts and use, for example, POSIX facilities instead? The discussion on the matter that I've seen so far usually boils down to:
system() is less flexible. (Fine with me)
It offers no control of the command being executed. (Fine with me, I just need a return value from the script)
It is not quite platform independent. (Now, this would be a concern. I would really love to see an example where it behaves differently on different platforms)
It is a security concern. (Again, this would be an issue. Can someone provide an example of a potential security problem with system()? )
Any other issues?
3) It is not quite platform independent (Now, this would be a concern. I would really love to see an example where it behaves differently on different platforms)
Well, for instance system("ls") would probably fail in Windows, since there is no ls command.
4) It is a security concern. (Again, this would be an issue. Can someone provide an example of a potential security problem with system() ? )
If the argument passed to system comes from user input, and not properly validated, it can be used to execute unwanted things with the privilege levels of the original executer. If its static content, its quite easy to find that within an executable image and modify it to do nasty things as well.
(3) If you just want a counterexample, for example grep behaves differently on Solaris vs Linux vs whatever.
(4) Your program's privileges are inherited by its spawned programs. If your application ever runs as a privileged user, all someone has to do is put their own program with the name of the thing you shell out too, and then can execute arbitrary code (this implies you should never run a program that uses system as root or setuid root).
(5) It will probably be saner to maintain in the long run to use the posix facilities because you won't have to rely on a specific set of external scripts or binaries already existing wherever your program runs.
I maintain a system that consists of several separate executables. In this case I have control over the permissions, names, calling conventions, security over all supported platforms. In this case, system() works just fine. The applications communicate through a RDBMS.
Again, as others have noted "The Devil's in the details".
Regarding security concerns, a classical example about (4) is the following scenario: imagine the user is prompted to give some directory name to be backed up into a std::string dirname; then you'll compute some backup directory name into a std::string backup and do
system((std::string{"cp -a "} + dirname + " " + backup).c_str())
Now think what happens if a malicious user enter foo bar; rm -rf $HOME; ls as the dirname and backup is /vol/backup_2015_fev/. The system command would execute
cp -a foo bar; rm -rf $HOME; ls /vol/backup_2015_fev/
which is not what you expected (all the user's $HOME would be deleted!). This is an example of code injection, and when using system you should ensure that it never happens (e.g. by sanitizing and/or escaping every user input related string)
Also, the PATH might not be what you believe it is (e.g. starting with /tmp/ and a malicious user having done ln -s /bin/rm /tmp/cp before your system runs).
I used the system() call in my CGI C++ app under windows and Linux too.
One problem I had was when using system() was not having the proper access rights to execute my skript with the web user.
I did not have that problem any more when using the CreateProcess() method.
Whatever command you want to execute just store that in a file c.txt. Pass that file to the execl() like as done below.
fd = open("c.txt", O_CREAT | O_RDWR, 00777);
write(fd,arr,sizeof(arr));
if(fork() == 0)
{
execl("/bin/sh", "sh", "-c","sh c.txt", (char *) 0);
}

C++ getenv always returns null value

I have just added the environment variable "DataDir", but the getenv function still returns null value.
Here is my code:
const char *ret = getenv("DataDir");
I restarted my computer and it done.
did you remember to export the variable before running the program? If you are using bash shell on linux, for example, you generally should use export DataDir="..."
On windows, if you set the environment variables using the system settings window, it will not immediately propagate to all of the running programs. If "I restarted my computer and it done." means "restarting the computer resolved the issue", then I believe that explains the problem. After changing the environment variable, try closing all programs and then start a CMD session (or visual studio) and run the program again
Are you running on Windows? Did you set the environment variable through the control panel? If so, that only affects processes that you start (programs that you launch) after you changed the setting. If you're running from a command prompt, and the command prompt didn't inherit the new environment variable, then your program won't inherit it either.
After rebooting, all new processes inherit the new environment variable.
On the other hand, if you set the variable and then run the program:
C:\>set DataDir=blah
C:\>.\my_program
then your program will inherit the variable (but it won't persist across a reboot).
Similar considerations apply on Linux and other systems, but the details differ.
Note that I'm only guessing, based on the symptoms you reported, what system you're using. In the future, it would be helpful to provide that information in the question (if it's not relevant we can ignore it).

How to detect launching from a "Startup"-folder shortcut?

I need to add the "Run when Windows starts" option to my program CintaNotes, but do not want to sacrifice the "cleanness" of it: it is a 100% portable freeware and should not leave traces in the system.
I've come up with the idea to autodetect running from the Startup shortcut and automatically minimizing to the system tray. Is there a way to do it? I'm using C++ and raw Winapi.
So:
- No writing to the registry
- No command line parameters
Thanks!
UPD: The question is NOT how to minimize to the system tray! The question is how can a program differentiate between being run normally and being run from a startup-folder shortcut without using registry and command-line parameters.
Your "cleanness" appears to be an artificial construct at best. If you're telling the user to create a shortcut in the start-up folder, you're already leaving a footprint (and, to be honest, there's little difference between "myprog.exe" and "myprog.exe -m"). In that case, there are some easier approaches than automagically trying to detect where you're running from.
I would simply provide a menu option in your program ("Install") which would then install the software to a fixed-disk location (as opposed to the flash drive), including the requisite Programs entry (Start, All Programs, CintaNotes).
As part of that process (or even after install), you can let them specify "Start with Windows" and then you create the start-up folder shortcut for the user with a command line option so your program can tell if it's running that way. There's no point in allowing "Start with Windows" unless the program's available (i.e., on the fixed disk, not the flash drive).
Your user need never have to worry about creating shortcuts at all, let alone ones with parameters. And this gives your program the control over how it's run - two modes, "installed" (and start minimized) or "running without installing first" (and start normal).
Something like finding the directory of the executable won't work simply because the start-up folder item that starts your program is likely to be a shortcut to it, so you won't have that path.
I think this is a classic case of asking the wrong question. In answer to your specific question, I say: no, there is no way to tell that you've been launched from a start up folder entry without some command-line parameters. But, I've been wrong before, just ask my wife :-). Some-one else may well know a way.
Adding this an an edit since comments don't allow enough space:
You ask:
What do you think of just disabling the "Start when Windows starts" option when program detects it is being run from the flash drive? I guess there's a way to detect this.
That's a good idea since it doesn't make sense to allow automatic running until it's installed (since the flash drive may not be there). One possibility:
1/ Running from flash, you start with "myprog.exe" since you just double-clicked the executable and you run in a normal window. This presents the option to "Install to fixed disk" but not "Start with Windows". As part of the install process, you may allow them to set up the installed copy to "Start with Windows" but not the current running copy.
2/ Your installed program can be set up to run as "myprog.exe -i", since you create the item in Start/AllPrograms. This would disable "Install to fixed disk" but allow you to toggle "Start with Windows". You can choose whether you want explicit running (by the user) to start normal or minimized (see (3)).
3/ The shortcut in StartUp can be "myprog.exe -s" (again, you control this because you created it). This is identical to (2) but starts minimized (if (2) started minimized anyway, there's no distinction between (2) and (3) and no reason for different command-line options).
That way, each option can have different behavior as you see fit.
Even though you have already solver the problem I just wanted to say that it's possible to detect if the program was launched from shortcut. Once you have the shortcut path you can compare it to startup folder.
See the section "Detect if an executable was started from a Short-Cut
" at Undocumented CreateProcess
Check the registry for this key.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run and add a new String key with the path of your application as value. and use NOTIFYICONDATA structure for minimizing your application to the tray.
Why don't you use an argument to start the application minimized like:
YourProgram.exe -m

Launch web page from my application in Linux

I have an application that launches a webpage in the "current" browser when the user selects it. This part of my app works fine in the Windows version but I can't figure out how to do this in Linux build.
Right now the Linux version is hardcoded for Firefox in a specific directory and runs a new instance of it each time and doesn't show the URL that I pass in. I would like it to NOT launch a new version each time but just open a new page in the current open one if it is already running.
For windows I use:
ShellExecute(NULL,"open",filename,NULL,NULL,SW_SHOWNORMAL);
For Linux I currently use:
pid_t pid;
char *args[2];
char *prog=0;
char firefox[]={"/usr/bin/firefox"};
if(strstri(filename,".html"))
prog=firefox;
if(prog)
{
args[0]=(char *)filename;
args[1]=0;
pid=fork();
if(!pid)
execvp(prog,args);
}
If you're writing this for modern distros, you can use xdg-open:
$ xdg-open http://google.com/
If you're on an older version you'll have to use a desktop-specific command like gnome-open or exo-open.
xdg-open is the new standard, and you should use it when possible. However, if the distro is more than a few years old, it may not exist, and alternative mechanisms include $BROWSER (older attempted standard), gnome-open (Gnome), kfmclient exec (KDE), exo-open (Xfce), or parsing mailcap yourself (the text/html handler will be likely be a browser).
That being said, most applications don't bother with that much work -- if they're built for a particular environment, they use that environment's launch mechanisms. For example, Gnome has gnome_url_show, KDE has KRun, most terminal programs (for example, mutt) parse mailcap, etc. Hardcoding a browser and allowing the distributor or user to override the default is common too.
I don't suggest hardcoding this, but if you really want to open a new tab in Firefox, you can use "firefox -new-tab $URL".
A note for xdg-open: check http://portland.freedesktop.org/wiki/ , section "Using Xdg-utils"; it states that you can include the xdg-open script in your own application and use that as fallback in case the target system doesn't have xdg-open already installed.
If you don't want to involve additional applications, just use the built-in remote control commands of firefox. E.g:
firefox -remote 'openurl(http://stackoverflow.com)'
Se detailed usage at http://www.mozilla.org/unix/remote.html