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

Package:
libglib2.0-bin
Source:
glib2.0
Description:
Programs for the GLib library
Submitter:
Norbert Preining
Date:
2017-10-07 16:39:03 UTC
Severity:
important
#877936#5
Date:
2017-10-07 14:38:17 UTC
From:
To:
Hi,

gio would be a nice option to use from other programs written in any kind of
language to open files.

Unfortunately, there seems to be no way to get the same behavior as of the
command line:

$ 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.

This is very unfortunate and counter-intuitive and useless.

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.

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

All the best

Norbert

#877936#10
Date:
2017-10-07 16:18:55 UTC
From:
To:
`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?
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.

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.

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

#877936#15
Date:
2017-10-07 16:30:31 UTC
From:
To:
Hi Simon,

Actually, I am writing in Scala, so not what-so-ever introspection. I just
want to call an external program to open a pdf or txt file.

Of course, this is a trival thing to spawn just another java thread and
execute gio, but it doesn't answer the question why the program gio works
differently on the command line or called from a program.

No. I tried it several times. Both with Perl and Scala. In all cases
when there are calls based on exec or system or similar, gio does not
return immediately.

My guess is that it checks for an attached tty.

Yes and no:

In the shell/prompt:

$ evince foo.pdf
	does return after evince is closed
$ gio foo.pdf
	does return *immediately*


Called from Perl/Scala/whatever other prog language

evince foo.pdf
	does return after evince is closed
gio foo.pdf
	does return after goo -> evince is closed

No, that is wrong.

	gio open foo.pdf

immediately returns to the prompt on an interactive shell, even when there is
no other instance of the respective pdf viewer running.

But called from a non-interactive shell/program, it returns only after the program
has terminated.

Norbert