I want to open an image, and in Windows I do:
#include <windows.h>
..
ShellExecute(NULL, "open", "https://gsamaras.files.wordpress.com/2018/11/chronosgod.png", NULL, NULL, SW_SHOWNORMAL);
I would like to use a Linux approach, where it's so much easier to run something on the fly. Example:
char s[100];
snprintf(s, sizeof s, "%s %s", "xdg-open", "https://gsamaras.files.wordpress.com/2018/11/chronosgod.png");
system(s);
In my Ubuntu, it works. However, when running that in Wandbox (Live Demo), or in any other online compiler, I would most likely get an error:
sh: 1: xdg-open: not found
despite the fact that these online compilers seem to live in Linux (checked). I don't expect the online compiler to open a browser for me, but I did expect the code to run without an error. Ah, and forget Mac (personal laptop, limiting my machines).
Since I have no other Linux machine to check, my question is: Can I expect that this code will work in most of the major Linux distributions?
Maybe the fact that it failed on online compilers is misleading.
PS: This is for my post on God of Time, so no worries about security.
Although Antti Haapala already completely answered the question, I thought some comments about the approach, and an example function making safe use trivial, might be useful.
xdg-open
is part of desktop integration utilities from freedesktop.org, as part of the Portland project. One can expect them to be available on any computer running a desktop environment participating in freedesktop.org. This includes GNOME, KDE, and Xfce.Simply put, this is the recommended way of opening a resource (be it a file or URL) when a desktop environment is in use, in whatever application the user prefers.
If there is no desktop environment in use, then there is no reason to expect
xdg-open
to be available either.For Linux, I would suggest using a dedicated function, perhaps along the following lines. First, a couple of internal helper functions:
closeall(0)
tries hard to close all open file descriptors, anddevnullfd(fd)
tries to openfd
to/dev/null
. These are used to make sure that even if the user spoofsxdg-open
, no file descriptors are leaked; only the file name or URL is passed.On non-Linux POSIXy systems, you can replace them with something more suitable. On BSDs, use
closefrom()
, and handle the firstULONG_MAX
descriptors in a loop.The
xdg_open(file-or-url)
function itself is something along the lines ofAs already mentioned, it tries hard to close all open file descriptors, redirects the standard streams to
/dev/null
, ensures the effective and real identity matches (in case this is used in a setuid binary), and passes success/failure using the child process exit status.The
setresuid()
andsetresgid()
calls are only available on OSes that have saved user and group ids. On others, useseteuid(uid)
andsetegid()
instead.This implementation tries to balance user configurability with security. Users can set the
PATH
so that their favouritexdg-open
gets executed, but the function tries to ensure that no sensitive information or privileges are leaked to that process.(Environment variables could be filtered, but they should not contain sensitive information in the first place, and we don't really know which ones a desktop environment uses. So better not mess with them, to keep user surprises to a minimum.)
As a minimal test
main()
, try the following:As the SPDX license identifier states, this example code is licensed under Creative Commons Zero 1.0. Use it any way you wish, in any code you want.
The
xdg-open
is part of thexdg-utils
. They're almost always installed with the GUI desktop of any Linux distribution.A Linux distribution can be installed without any Graphical User Interface, on servers say, and most probably then they would lack
xdg-open
.Instead of
system
, you could - and should - usefork
+exec
- ifexec
fails thenxdg-open
could not be executed.The online compilers most probably don't have any Desktop GUI installed on them, thus the lack of that utility.