www.delorie.com/djgpp/bugs/show.cgi   search  
Bug 000095

When Created: 07/11/1996 13:52:24
Against DJGPP version: 2.00
By whom: eliz@is.elta.co.il
Abstract: `spawn*' and `system' cannot execute XCOPY from DOS 6.x
When you spawn some programs from a DJGPP program they don't work
correctly.  An example in point is XCOPY from DOS 6.x (the version from
DOS 5.0 works): it prints an error message about "Invalid drive
specification" and refuses to work.

Note added: 07/11/1996 13:58:44
By whom: eliz@is.elta.co.il
The cause of this is the fact that the function that actually calls
Int 21h/AX=4B00h (DOS Exec) function (`direct_exec_tail' on `dosexec.c')
doesn't create the 2 FCBs and doesn't point relevant parts of the Exec
parameter block to those FCBs.  It seems that at least XCOPY from DOS
6.x actually looks at the FCBs and wants them to hold reasonable values,
at least in the drive field.

Workaround added: 07/11/1996 14:00:58
By whom: eliz@is.elta.co.il
Invoke the programs that won't run via COMMAND.COM, like this:

    system ("command.com /c xcopy d:\file b:\");

Solution added: 07/11/1996 14:05:10
By whom: eliz@is.elta.co.il
Apply the following patch to dosexec.c:

*** src/libc/dos/process/dosexec.c~2    Sat Apr 27 21:19:44 1996
--- src/libc/dos/process/dosexec.c      Wed Jul 10 21:46:10 1996
***************
*** 13,18 ****
--- 13,19 ----
  #include <libc/dosexec.h>
  #include <libc/unconst.h>
  #include <libc/dosio.h>
+ #include <libc/farptrgs.h>

  extern char **environ;

*************** static int direct_exec_tail(const char *
*** 53,61 ****
--- 54,64 ----
    const char *progname;
    unsigned proglen;
    int i;
+   unsigned long fcb1_la, fcb2_la, fname_la;

    sync();

+   /* The pathname of the executable to run.  */
    proglen = strlen(program)+1;
    if(_USE_LFN) {
      dosmemput(program, proglen, tbuf);
*************** static int direct_exec_tail(const char *
*** 80,111 ****
    parm_la = talloc(sizeof(Execp));

    dosmemput(progname, proglen, program_la);
!
    arg_header[0] = strlen(args);
    arg_header[1] = '
';
    dosmemput(arg_header, 1, arg_la);
    dosmemput(args, strlen(args), arg_la+1);
    dosmemput(arg_header+1, 1, arg_la+1+strlen(args));

    do {
      env_la = talloc(1);
    } while (env_la & 15);
    talloc(-1);
    for (i=0; envp[i]; i++)
    {
      env_e_la = talloc(strlen(envp[i])+1);
      dosmemput(envp[i], strlen(envp[i])+1, env_e_la);
    }
    arg_header[0] = 0;
!   arg_header[1] = 1;
    arg_header[2] = 0;
    dosmemput(arg_header, 3, talloc(3));
    env_e_la = talloc(proglen);
    dosmemput(progname, proglen, env_e_la);

!   parm.eseg = env_la / 16;
!   parm.argseg = arg_la / 16;
!   parm.argoff = arg_la & 15;
    dosmemput(&parm, sizeof(parm), parm_la);

    r.x.ax = 0x4b00;
--- 83,159 ----
    parm_la = talloc(sizeof(Execp));

    dosmemput(progname, proglen, program_la);
!
!   /* The command-line tail.  */
    arg_header[0] = strlen(args);
    arg_header[1] = '
';
    dosmemput(arg_header, 1, arg_la);
    dosmemput(args, strlen(args), arg_la+1);
    dosmemput(arg_header+1, 1, arg_la+1+strlen(args));

+   /* The 2 FCBs.  Some programs (like XCOPY from DOS 6.x) need them.  */
+   fcb1_la = talloc(16);              /* allocate space for 1st FCB */
+   fname_la = arg_la + 1;       /* first character of command tail */
+   r.x.ax = 0x2901;           /* AL = 1 means skip leading separators */
+   r.x.ds = fname_la / 16;      /* pointer to 1st cmd argument */
+   r.x.si = fname_la & 15;
+   r.x.es = fcb1_la / 16;       /* pointer to FCB buffer */
+   r.x.di = fcb1_la & 15;
+   __dpmi_int (0x21, &r);
+
+   /* We cannot be sure that Int 21h/AX=2901h parsed the entire
+      first command-line argument (it might not be a filename
+      at all!).  We need to get to the next command-line arg
+      before calling 2901 again.  2901 returns the pointer to
+      first unparsed character in DS:SI.
+
+      Note that, in case there is no second command-line argument,
+      the following loop is terminated by the trailing CR which
+      ends the command-line tail.  */
+   for (_farsetsel(_dos_ds), fname_la = ((unsigned)r.x.ds) * 16 + r.x.si;
+        !isspace(_farnspeekb(fname_la));
+        fname_la++)
+     ;
+
+   fcb2_la = talloc(16);
+   r.x.ax = 0x2901;
+   r.x.ds = fname_la / 16;      /* begin parsing 2nd arg from here */
+   r.x.si = fname_la & 15;
+   r.x.es = fcb2_la / 16;
+   r.x.di = fcb2_la & 15;
+   __dpmi_int (0x21, &r);
+
+   /* The environment must be on a segment boundary, so get
+      to the first location in the transfer buffer whose
+      linear address is divisable by 16.  */
    do {
      env_la = talloc(1);
    } while (env_la & 15);
    talloc(-1);
+
+   /* The environment, terminated by an extra NULL char.  */
    for (i=0; envp[i]; i++)
    {
      env_e_la = talloc(strlen(envp[i])+1);
      dosmemput(envp[i], strlen(envp[i])+1, env_e_la);
    }
    arg_header[0] = 0;
!
!   /* The name of the program that owns the environment.  */
!   arg_header[1] = 1;  /* the number of strings (1, little-endian) */
    arg_header[2] = 0;
    dosmemput(arg_header, 3, talloc(3));
    env_e_la = talloc(proglen);
    dosmemput(progname, proglen, env_e_la);

!   /* Prepare the parameter block and call Int 21h/AX=4B00h.  */
!   parm.eseg     = env_la / 16;
!   parm.argseg = arg_la / 16;
!   parm.argoff = arg_la & 15;
!   parm.fcb1_seg = fcb1_la / 16;
!   parm.fcb1_off = fcb1_la & 15;
!   parm.fcb2_seg = fcb2_la / 16;
!   parm.fcb2_off = fcb2_la & 15;
    dosmemput(&parm, sizeof(parm), parm_la);

    r.x.ax = 0x4b00;

Note added: 07/14/1996 14:23:51
By whom: terra@diku.dk (Morten Welinder)
Actually, if memory serves, most debuggers and other libraries out
there get this wrong.  (Turbo Debugger, Turbo C, and Borland Pascal
are known to get it wrong.)

Just calling the parse function twice is not good enough when the
first file name includes a path character, but just calling twice
is exactly what the above products do.  Now, try convincing Borland
that any of their products are buggy, ...

One more thing: note that backslash-newlines in the patch were
mangled by the bug tracking system.  You should be able to guess
where.

Fixed in version 2.01 on 07/26/1996 00:35:12
By whom: dj@delorie.com



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