delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1997/09/09/07:25:05

Date: Tue, 9 Sep 1997 14:21:03 +0300 (IDT)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
To: Molnar Laszlo <molnarl AT cdata DOT tvnet DOT hu>
cc: DJGPP workers <djgpp-workers AT delorie DOT com>
Subject: Re: a patch for system()
In-Reply-To: <3413F6B4.6D5CEBFE@cdata.tvnet.hu>
Message-ID: <Pine.SUN.3.91.970909142028.7143E-100000@is>
MIME-Version: 1.0

On Mon, 8 Sep 1997, Molnar Laszlo wrote:

> I have a problem with system(), when I try to run a non-existing
> program. I always have SHELL=path/to/bash when working with djgpp
> programs. But perl says, that I shouldn't start a shell with system()
> when don't need. So I simply check for some magic character in the
> command line, and if I find none, I set __sys_flags to use
> __system_emulate_command.

Isn't this dangerous?  The test to see whether the shell is required
is much more complicated than looking for special characters.  For
example: is `:' a character that calls for the shell or not?  If it
is, you are going to call the shell for every DOS pathname which
includes a drive letter; if it isn't, you will fail for commands that
begin with a `:' (which only unixy shell knows about).  And this is in
no way a single example; see job.c from the GNU Make distribution, for
an example of how a complete treatment of this issue looks like.

I think the overhead of calling Bash is not too much to pay for
correct operation.  After all, we all know that whoever uses DOS
*must* pay something for having GNU tools, right?

> And here is my problem. When system() tries to
> run a nonexistent program, its "last resort" is to pass it to the shell.
> If the shell was command.com, I get 0 as the return code, and if it was
> bash, I get 127. Instead of -1.

The problem with 127 in the case of Bash can be handled (see below).
But I don't see any way to handle the problem with COMMAND.COM
returning 0.  You could, of course, have a table of its internal
commands so that we know when the command is internal, but even then
commands like "copy foo bar" will fail when foo doesn't exist, and
still return 0 status code.  Not to mention the possibility that the
user has some weird shell with a different set of internal commands
(for example, COMMAND.COM has a provision to add internal commands
implemented in a TSR via a special callback API).

Sorry, this is just too damn messy; I didn't find any reasonable
solution to it at the time, so things were left as they were before,
as they are in every other DOS compiler for these cases: when
COMMAND.COM is called, you are in trouble, period.  People who use
Perl should be told to set SHELL to Bash, as God intended.

> Here is the patch I use:
>
> *** system.c~   Sun Aug 31 15:40:56 1997
> --- system.c    Sun Sep  7 22:54:30 1997
> ***************
> *** 245,249 ****
>         endcmd = 0;
>       }
> !     if (endcmd
>         && (stricmp (endcmd, "exe") == 0
>             || stricmp (endcmd, "com") == 0
> --- 245,249 ----
>         endcmd = 0;
>       }
> !     if ((sys_flags & __system_emulate_command) || endcmd
>         && (stricmp (endcmd, "exe") == 0
>             || stricmp (endcmd, "com") == 0

This isn't right, I think: it causes Perl to fail all the internal
commands of the shell.  Is this what you want?  Does Perl on Unix fail
to execute commands internal to the shell?

Another problem with this is that if the shell has its own places
(other than $PATH) to search for its scripts, this patch breaks those
cases also, if the name of the script gets here with no extension.

If we want to get -1 in the case of Bash, we need to patch dosexec.c,
I think.  The following fragment from the end of direct_exec_tail is
probably the culprit, since it doesn't sign-extend 127 to -1.
Comments?


  /* AH holds the ``system exit code'' which is non-zero if the
     child was aborted by Ctrl-C, or Critical Device error (also
     if the child installs itself as a TSR).  */
  if (r.h.ah && r.h.ah != 3) /* 3 means it exited as TSR (is it ``normal''?) */
    {
      errno = EINTR;	/* what else can we put in `errno'? */
      return ( ((r.h.ah == 1 ? SIGINT : SIGABRT) << 8) | r.h.al );
    }
  return r.h.al;	/* AL holds the child exit code */
}

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019