Bug#877936: gio: different behavior when called from shell or program - does not return immediately when called from program

Simon McVittie smcv at debian.org
Sat Oct 7 16:18:55 UTC 2017


On Sat, 07 Oct 2017 at 23:38:17 +0900, Norbert Preining wrote:
> gio would be a nice option to use from other programs written in any kind of
> language to open files.

`gio open` is just a command-line shim around public libgio APIs, so you
might want to consider using those same APIs from your program: that will
provide control over whether they happen synchronously or asynchronously,
and the best possible efficiency. This is usually done via some generic
wrapper for GObject-Introspection, like python3-gi. If you're writing
in Perl, libglib-object-introspection-perl seems to be the right library?

> I want to open a viewer but keep my program running, but the current
> mode hangs and waits for the viewer to terminate until execution in
> the calling program continues.

If libgio APIs aren't available to you for whatever reason, or if
you would prefer to use the "launch a utility" approach, you can make
any subprocess asynchronous by using better tools than Perl's backtick
operator. Unfortunately I'm not familiar with what the best tool is for
this in the Perl world. In languages that I'm more familiar with, I'd
be using GLib's GSubprocess or g_spawn_async(), or Python's subprocess
module - I'd recommend using the closest available equivalent of those
in your chosen language.

perl-modules seems to include IPC::Cmd, which looks promising. The
Proc:: CPAN hierarchy (libproc-*-perl) are also worth considering,
as is IPC::Run (which is what I generally use to start subprocesses from
Perl myself, but I don't know whether a more experienced Perl developer
would do the same).

As a last resort, it's possible to implement fork-and-exec in pure Perl,
although I would strongly recommend using library code instead.

I would very strongly recommend using an API that takes an argument
vector as an array or list, such as:

* Perl's IPC::Cmd::run_forked(['some', 'command']) (with the first
  argument being an array reference)
* Python's subprocess.Popen(['some', command'])
* C's posix_spawn()

rather than an API that takes a shell one-liner:

* Perl's IPC::Cmd::run_forked('some command') (with the first argument
  being a string)
* Perl's `some command` or qx{some command}
* Python's subprocess.Popen('some command', shell=True)
* Python's os.system()
* C's system()

A shell-based API is very likely to lead to shell injection
vulnerabilities (for example if the filename of the PDF you're viewing
contains shell metacharacters), which would be bad.

Unfortunately, what the backtick/qx operator does in Perl is constrained
by backwards compatibility, but that doesn't mean you have to be
constrained by that historical mistake.

> $ gio open foo.pdf
> ....# opens foo.pdf in my defined viewer
> $ 
> 
> gio returns *immediately* after opening the file and does *NOT* wait for the
> viewer to be closed.
> 
> Doing the same from perl:
> ..
> `gio open foo.pdf`;
> ...
> 
> Does *INDEED* wait for the viewer to be terminated.

I'd be surprised if that's the cause of the difference you're seeing.
Are you sure the difference is in where you're calling it from, and not
some other factor like whether the PDF viewer was already running?
Does the behaviour of `gio open` differ from what happens when you run
the configured PDF viewer directly? (To have an apples-to-apples comparison
you will need to make sure to be consistent about whether/when you kill
any background processes belonging to that viewer.)

In applications that use D-Bus or other IPC for single-instance, it's
somewhat common for the first instance that is run to be long-lived,
while the second and subsequent instances just send an IPC request to
the first instance, wait for confirmation that it has been received,
and exit. I would personally argue that this is an application bug - the
application should either always be long-lived (by waiting for a remote
instance contacted via IPC to close the document, if necessary), or
always be short-lived (by either contacting a remote instance via IPC
or backgrounding itself) - but if it's a bug, it's a common one.

> gio should have a command line switch that defines the behavior on return
> values.

If the invoked application backgrounds itself or does the "IPC to remote
instance, then exit" pattern, then there is nothing that `gio open`
can do to wait for completion, so waiting for completion seems like an
impossible behaviour to guarantee.

An option to *never* wait for completion might be more achievable, but
a caller who wants that can always get it by launching gio
asynchronously, so I'm not sure that it would be particularly useful.

    smcv



More information about the pkg-gnome-maintainers mailing list