Date: Tue, 9 Sep 1997 14:21:03 +0300 (IDT) From: Eli Zaretskii To: Molnar Laszlo cc: DJGPP workers Subject: Re: a patch for system() In-Reply-To: <3413F6B4.6D5CEBFE@cdata.tvnet.hu> Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Precedence: bulk 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 */ }