www.delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/1996/07/11/14:22:23

Date: Thu, 11 Jul 1996 21:17:45 +0200 (IST)
From: Eli Zaretskii <eliz AT is DOT elta DOT co DOT il>
To: djgpp-workers AT delorie DOT com
Subject: Bug in spawn/system functions
Message-Id: <Pine.SUN.3.91.960711210956.7736I-100000@is>
Mime-Version: 1.0

There is a subtle bug in the code that invokes child programs.  The 
function `direct_exec_tail' doesn't create valid FCBs and doesn't point 
two relevant parts of the Exec parameter block to those FCBs.  Most 
programs ignore these fields, but some (like XCOPY from DOS 6.2x) 
actually access them and refuse to work if their content is illegal.

The following patches solve that problem.  (I also submitted them to 
the bug-tracking system.)

*** 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] = '\r';
    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] = '\r';
    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;

- Raw text -


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