[haiku-bugs] Re: [Haiku] #12298: Running shell commands from an app fails

  • From: "ttcoder" <trac@xxxxxxxxxxxx>
  • Date: Thu, 03 Sep 2015 15:03:21 -0000

#12298: Running shell commands from an app fails
-------------------------------------+----------------------------
Reporter: humdinger | Owner: axeld
Type: bug | Status: new
Priority: blocker | Milestone: R1/beta1
Component: Servers/launch_daemon | Version: R1/Development
Resolution: | Keywords:
Blocked By: | Blocking:
Has a Patch: 0 | Platform: All
-------------------------------------+----------------------------

Comment (by ttcoder):

Thanks pulkomandy!

First some code:

{{{
#include <errno.h>
#include <Application.h>
#include <Alert.h>

int main()
{
BApplication app("application/test");

#if 1
if(write(STDOUT_FILENO, "dummy", 0) < 0)
{
// add this work-around for #12298 in applications that
rely on ::system() et al, and thus directly or indirectly require calls to
write() like this one
// write( STDOUT_FILENO, buf, buflen )
// to *not* return an error even when run from Tracker
(where write(stdout) returns -1 with errno 0x80006000):

int devnull_wr = open("/dev/null", O_WRONLY); // careful
to create the new fd _before_ calling close(1)
close(STDOUT_FILENO);
dup2(devnull_wr, STDOUT_FILENO);
close(devnull_wr);
//+: stderr, maybe also stdin

// write(stdout...) should work from here on
}
#endif

char buf[100] = "";

sprintf(buf, "fileno(stdout)=%d isatty=%d", fileno(stdout),
isatty(STDOUT_FILENO));
(new BAlert("alert", buf, "ok"))
->Go();

//int clo = close( STDOUT_FILENO );
//clo = close( STDOUT_FILENO ); // calling close a second time
does return -1 in all cases, so the SECOND call behaves normally
//sprintf(buf, "close() returns 0x%x", clo);
//(new BAlert("alert", buf, "ok"))->Go();

errno = 0;
int checkstdout = write(STDOUT_FILENO, "dummy", 0); // a 0 length
write works just as well
sprintf(buf, "write() returns %d errno=0x%x", checkstdout,
errno);
(new BAlert("alert", buf, "ok"))->Go();
//we get errno 0x80006000 (Bad file descriptor) when run from
Tracker indeed (unless the work-around block is activated)

// the "moment of truth" test (emulates what my NetServPreflet
does):
int grep = system("grep 'sshd:' /etc/passwd");
sprintf(buf, "GREP RETURNS:%d", grep);
(new BAlert("alert", buf, "ok"))->Go();

return 0;
}

}}}

Comments:

Work-around wise, the above if-1-endif block seems to work very well.

Found a weird aspect to this bug though.. And unlike my previous
'findings' that might not be all that relevant, that one does seem wrong:
when run from Tracker, close() accepts closing stdout (returns 0) even
though calling write() on stdout returns -1, and sets errno to 0x80006000
(Bad file descriptor) So that would be a bug in close() I guess, how can
it accept closing a "bad file descriptor"

Also regarding the "10 files already opened" suspicion, found some info
that "open always returns lowest unused fd" which would mean that
applications launched from Tracker come up with 10 files already opened
(maybe inherited from parent after being forked ?). Does that make sense ?
Would that constitute a security breach of sorts, in a multi-user
environement, for Tracker/Registrar to pass its own file descs to every
apps it spawns ? Maybe an FD_CLOEXEC flag would help here

--
Ticket URL: <https://dev.haiku-os.org/ticket/12298#comment:20>
Haiku <https://dev.haiku-os.org>
Haiku - the operating system.

Other related posts: