After an evaluation, GNOME has moved from Bugzilla to GitLab. Learn more about GitLab.
No new issues can be reported in GNOME Bugzilla anymore.
To report an issue in a GNOME project, go to GNOME GitLab.
Do not go to GNOME Gitlab for: Bluefish, Doxygen, GnuCash, GStreamer, java-gnome, LDTP, NetworkManager, Tomboy.
Bug 679691 - Add g_spawn_check_exit_status()
Add g_spawn_check_exit_status()
Status: RESOLVED FIXED
Product: glib
Classification: Platform
Component: general
unspecified
Other All
: Normal normal
: ---
Assigned To: gtkdev
gtkdev
Depends on:
Blocks: 672102
 
 
Reported: 2012-07-10 15:40 UTC by Colin Walters
Modified: 2012-07-13 09:07 UTC
See Also:
GNOME target: ---
GNOME version: ---


Attachments
Add g_spawn_check_exit_status() (14.53 KB, patch)
2012-07-10 15:40 UTC, Colin Walters
none Details | Review
sample gnome-session patch (2.03 KB, text/plain)
2012-07-10 15:42 UTC, Colin Walters
  Details
Add g_spawn_check_exit_status() (15.88 KB, patch)
2012-07-10 20:38 UTC, Colin Walters
committed Details | Review
win32: fix build g_spawn_check_exit_status() with mingw (1.46 KB, patch)
2012-07-11 17:43 UTC, Marc-Andre Lureau
reviewed Details | Review
win32: fix build g_spawn_check_exit_status() with mingw (2.18 KB, patch)
2012-07-11 19:01 UTC, Marc-Andre Lureau
committed Details | Review

Description Colin Walters 2012-07-10 15:40:42 UTC
Many (if not "almost all") programs that spawn other programs via
g_spawn_sync() or the like simply want to check whether or not the
child exited successfully, but doing so requires use of
platform-specific functionality and there's actually a fair amount of
boilerplate involved.

This new API will help drain a *lot* of mostly duplicated code in
GNOME, from gnome-session to gdm.  And we can see that some bits even
inside GLib were doing it wrong; for example checking the exit status
on Unix, but ignoring it on Windows.
Comment 1 Colin Walters 2012-07-10 15:40:44 UTC
Created attachment 218434 [details] [review]
Add g_spawn_check_exit_status()
Comment 2 Colin Walters 2012-07-10 15:42:55 UTC
Created attachment 218435 [details]
sample gnome-session patch
Comment 3 Dan Winship 2012-07-10 16:14:33 UTC
Comment on attachment 218434 [details] [review]
Add g_spawn_check_exit_status()

>+ * If for some reason you do need to make your program behave
>+ * differently if a child (for example) exits with code 1 versus when
>+ * it exits with code 2, you will need to use platform-specific APIs
>+ * such as Unix <literal>WIFEXITED()</literal> and
>+ * <literal>WEXITSTATUS()</literal>.

Hm... I thought I'd made this comment in the GSubprocess bug, but maybe it was just on IRC. Anyway, it would be nice to have a G_PROCESS_EXIT_ERROR GError domain, and then in the exited-with-non-0-status case, do

	  g_set_error (error, G_PROCESS_EXIT_ERROR, WEXITSTATUS (exit_status),
		       _("Child process exited with code %ld"),
		       (long) WEXITSTATUS (exit_status));

which lets you extract the exit status from the GError if you want it.
Comment 4 Colin Walters 2012-07-10 16:31:48 UTC
(In reply to comment #3)
> (From update of attachment 218434 [details] [review])
> >+ * If for some reason you do need to make your program behave
> >+ * differently if a child (for example) exits with code 1 versus when
> >+ * it exits with code 2, you will need to use platform-specific APIs
> >+ * such as Unix <literal>WIFEXITED()</literal> and
> >+ * <literal>WEXITSTATUS()</literal>.
> 
> Hm... I thought I'd made this comment in the GSubprocess bug, but maybe it was
> just on IRC. Anyway, it would be nice to have a G_PROCESS_EXIT_ERROR GError
> domain, and then in the exited-with-non-0-status case, do
> 
>       g_set_error (error, G_PROCESS_EXIT_ERROR, WEXITSTATUS (exit_status),
>                _("Child process exited with code %ld"),
>                (long) WEXITSTATUS (exit_status));
> 
> which lets you extract the exit status from the GError if you want it.

But what do I do if it was killed by a signal?
Comment 5 Dan Winship 2012-07-10 17:13:32 UTC
just return G_SPAWN_ERROR_FAILED like you do now; it's MUCH rarer that you'd actually care *which* signal killed the process (for any reason other than putting it into the error message).
Comment 6 Colin Walters 2012-07-10 17:19:48 UTC
(In reply to comment #5)
> just return G_SPAWN_ERROR_FAILED like you do now; it's MUCH rarer that you'd
> actually care *which* signal killed the process (for any reason other than
> putting it into the error message).

Can you point me to code that cares about the exit status and doesn't care about the signal?  gnome-session does this (it specifically checks for exit code 1 and special cases it), but honestly I think what it's doing is total crack.

My guess is that most code that is looking at the exit code is trying to do custom error messages.  And if you're doing custom error messages, you probably want to know which signal too.  Of course, I'd also guess that most code that presently has custom error messages would be totally fine with the ones we have now in g_spawn_check_exit_status(); at least I feel that's the case for the gnome-session patch (which note is a different code section than the total crack one above).
Comment 7 Dan Winship 2012-07-10 19:19:04 UTC
(In reply to comment #6)
> Can you point me to code that cares about the exit status and doesn't care
> about the signal?

They're completely different sorts of things; programs intentionally exit with specific non-0 status codes to communicate information to their caller. Exiting on a signal is almost always unintentional on the part of the exiting program, and so carries very little information.

grepping through a jhbuild, I guess I should have said "*command line* programs" above:

  - metacity invokes zenity and looks at the exit status to determine,
    eg, what button was clicked. (Zenity can do lots of stuff with exit
    status, and in particular, it differentiates "user clicked cancel"
    from internal errors like "couldn't find .ui file".)

  - NM uses the exit codes of pppd and dnsmasq to provide specific error
    messages explaining what failed. ("man pppd" and search for "EXIT
    STATUS")

  - The evolution spamassassin and bogofilter plugins use the exit status
    of the program they call to determine whether the message is spam or not
    (and, as in the zenity case, to differentiate that from "something went
    wrong")

So, not super common I guess, but it's there.

(There are also lots of programs like dbus-launch and pk-spawn that "re-throw" the exit status of their child.)
Comment 8 Colin Walters 2012-07-10 20:02:36 UTC
(In reply to comment #7)
> (In reply to comment #6)
> > Can you point me to code that cares about the exit status and doesn't care
> > about the signal?
> 
> They're completely different sorts of things; programs intentionally exit with
> specific non-0 status codes to communicate information to their caller. Exiting
> on a signal is almost always unintentional on the part of the exiting program,
> and so carries very little information.

Ok...so code would look like:

  GError *spawn_error = NULL;

  /* g_spawn_sync(...) */

  if (!g_spawn_check_exit_status (exit_status, &spawn_error))
    {
      if (spawn_error->domain == G_SPAWN_EXIT_ERROR)
        {
          if (spawn_error->code == 0)
            /* Ok was pressed */
          else if (spawn_error->code == 1)
            /* Cancel was pressed */
          else
            {
              g_propagate_error (error, spawn_error);
              goto out;
            }
        }
      else
        {
          g_propagate_error (error, spawn_error);
          goto out;
        }
    }

But the thing is, it's basically the same amount of code to do #include <sys/wait.h>, and:

    if (WIFEXITED (exit_status))
      {
        if (WEXITSTATUS (exit_status) == 1)
          /* OK */
        else if (WEXITSTATUS (exit_status) == 2)
          /* Cancel */
        else
          {
            g_spawn_check_exit_status (exit_status, error);
            goto out;
          }
      }
    else
      {
        g_spawn_check_exit_status (exit_status, error);
        goto out;
      }
    }

What I'm not sure of though is whether you can use exit codes on Windows in the same way you can on Unix.  From my reading of http://msdn.microsoft.com/en-us/library/windows/desktop/ms682658%28v=vs.85%29.aspx you probably can...but I don't think any of the listed projects care about portability to Windows.
Comment 9 Dan Winship 2012-07-10 20:11:07 UTC
>  else
>    g_propagate_error (error, spawn_error);

well, I think these would mostly be in situations where the g_spawn* caller was also the final consumer of the GError. Eg, the metacity force-quit handler doesn't care that zenity segfaulted, it just wants to know whether or not it should continue with the force-quitting.

But yes, it's not any less code, just more glib-like (and bindable!)
Comment 10 Colin Walters 2012-07-10 20:38:16 UTC
Created attachment 218472 [details] [review]
Add g_spawn_check_exit_status()

Now using G_SPAWN_EXIT_ERROR
Comment 11 Matthias Clasen 2012-07-10 21:06:30 UTC
Review of attachment 218472 [details] [review]:

I like it. Feel free to commit after fixing the cosmetic issues.

::: gio/glib-compile-resources.c
@@ +330,3 @@
                 }
+	      
+	      /* Ugly...we shoud probably just keep stderr to our stderr */

that comment is hard to parse. 'keep stderr to our stderr' ?!

::: glib/gspawn.c
@@ +241,3 @@
+ *
+ * If @exit_status is non-%NULL, the platform-specific exit status of
+ * the child is stored there; see the doucumentation of

typo: doucumentation

@@ +836,3 @@
+ * on @exit_status directly.  Do not attempt to scan or parse the
+ * error message string; it may be translated and/or change in future
+ * versions of GLib.

Putting the example code from the bug in here would be nice.

@@ +837,3 @@
+ * error message string; it may be translated and/or change in future
+ * versions of GLib.
+ *

You're missing the documentation for the return value here.
Comment 12 Colin Walters 2012-07-10 21:58:03 UTC
(In reply to comment #11)

> Putting the example code from the bug in here would be nice.

I considered it but gspawn.c doesn't have any example code at all right now, and I'd be loath to add some just for people living in a state of sin^W^W^W interpreting error codes.  Plus the doc comment is already too long.

If anything I want to add more examples of how to use GSubprocess =)  The gio/tests/gsubprocess.c already uses G_SPAWN_EXIT_ERROR.
Comment 13 Colin Walters 2012-07-10 22:05:08 UTC
Attachment 218472 [details] pushed as f7abd3c - Add g_spawn_check_exit_status()
Comment 14 Marc-Andre Lureau 2012-07-11 17:35:12 UTC
unfortunately, that break windows compilation, (reopening to avoid extra bugs)
Comment 15 Colin Walters 2012-07-11 17:36:34 UTC
(In reply to comment #14)
> unfortunately, that break windows compilation, (reopening to avoid extra bugs)

Build logs?
Comment 16 Marc-Andre Lureau 2012-07-11 17:43:15 UTC
Created attachment 218576 [details] [review]
win32: fix build g_spawn_check_exit_status() with mingw

With mingw, only gspawn-win32.c is compiled, but it is missing some
new symbols
Comment 17 Marc-Andre Lureau 2012-07-11 17:53:29 UTC
(In reply to comment #15)
> (In reply to comment #14)
> > unfortunately, that break windows compilation, (reopening to avoid extra bugs)
> 
> Build logs?

  CCLD   libglib-2.0.la
Creating library file: .libs/libglib-2.0.dll.a
Cannot export g_spawn_check_exit_status: symbol not defined
Cannot export g_spawn_exit_error_quark: symbol not defined
collect2: error: ld returned 1 exit status
Comment 18 Colin Walters 2012-07-11 18:01:40 UTC
Review of attachment 218576 [details] [review]:

Oh...ugh.  Can you make the gspawn.c only apply to Unix then too?  Delete the #ifdef G_OS_UNIX?  Duplicating the error quark is mildly lame, but oh well.
Comment 19 Marc-Andre Lureau 2012-07-11 18:18:38 UTC
Review of attachment 218576 [details] [review]:

gspawn.c is compiled for anything but mingw apparently, so we may want to keep the #ifdef G_OS_UNIX, no?

AC_MSG_CHECKING(for gspawn implementation)
case "$host" in
  *-*-mingw*)
    GSPAWN=gspawn-win32.lo
    ;;
  *)
    GSPAWN=gspawn.lo
    ;;    
esac
AC_MSG_RESULT($GSPAWN)
AC_SUBST(GSPAWN)

For the quark, I thought about putting it elsewhere, but I had no good idea :)
Comment 20 Colin Walters 2012-07-11 18:39:10 UTC
(In reply to comment #19)
> Review of attachment 218576 [details] [review]:
> 
> gspawn.c is compiled for anything but mingw apparently, so we may want to keep
> the #ifdef G_OS_UNIX, no?
> 
> AC_MSG_CHECKING(for gspawn implementation)
> case "$host" in
>   *-*-mingw*)
>     GSPAWN=gspawn-win32.lo

I don't understand this...because gspawn.c will not compile on Windows in any configuration, right?  I mean, it uses fork() etc.  So we must not be supporting non-mingw win32 builds?
Comment 21 Dan Winship 2012-07-11 18:44:12 UTC
we don't support non-mingw builds via ./configure. There's a separate MSVC build system in build/win32 that you're allowed to not think about how it works.
Comment 22 Colin Walters 2012-07-11 18:55:31 UTC
(In reply to comment #21)
> we don't support non-mingw builds via ./configure. There's a separate MSVC
> build system in build/win32 that you're allowed to not think about how it
> works.

WALL OF UUIDS AND XML! MY EYES!!!

So...yeah I think this supports my assertion that we should remove the win32 code I thought would work from gspawn.c.
Comment 23 Marc-Andre Lureau 2012-07-11 19:01:54 UTC
Created attachment 218584 [details] [review]
win32: fix build g_spawn_check_exit_status() with mingw

With mingw, only gspawn-win32.c is compiled, but it is missing some
new symbols.
Comment 24 Colin Walters 2012-07-11 19:41:15 UTC
Review of attachment 218584 [details] [review]:

Go go gadget commit!
Comment 25 Jasper St. Pierre (not reading bugmail) 2012-07-11 20:57:03 UTC
(In reply to comment #22)
> WALL OF UUIDS AND XML! MY EYES!!!

also known as the systemd build system

(ok, I'll shut up, I promise)
Comment 26 Colin Walters 2012-07-13 03:25:59 UTC
Attachment 218584 [details] pushed as d9af425 - win32: fix build g_spawn_check_exit_status() with mingw
Comment 27 Christian Persch 2012-07-13 09:07:06 UTC
(In reply to comment #5)
> just return G_SPAWN_ERROR_FAILED like you do now; it's MUCH rarer that you'd
> actually care *which* signal killed the process (for any reason other than
> putting it into the error message).

I don't know if anything *actually* uses that, but this from the bash docs:

   The return status (*note Exit Status::) of a simple command is its
exit status as provided by the POSIX 1003.1 `waitpid' function, or
128+N if the command was terminated by signal N.

so I guess someone might care. (E.g. in g-t I emulate this behaviour.)