I have noted that FreeDOS 1.3 RC1 distributes a kernel 2042.  This kernel
seems to have serious issues concerning the redirection of file descriptors
and the creation of pipes.  I noted this when I tried to use the djgpp
port of Bash 4.17 on FreeDOS 1.2 and later on FreeDOS 1.3 RC1.  I use it
to configure gnu packages that I want to port to DOS.  An example of a
failing shell script snippet looks like this:


ac_subst_vars='am__EXEEXT_FALSE
am__EXEEXT_TRUE
SHELL'
{
  echo "cat >confsubs.awk <<_ACEOF" &&
  echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
  echo "_ACEOF"

} >confsubs.sh1


As can be seen the output shall be redirected to a file and certain values
are modified by piping them to sed which output also goes to the output file.
If this script is run by the bash port on MS-DOS 3.2 it looks perfect like
this:


cat >confsubs.awk <<_ACEOF
am__EXEEXT_FALSE!$am__EXEEXT_FALSE$ac_delim
am__EXEEXT_TRUE!$am__EXEEXT_TRUE$ac_delim
SHELL!$SHELL$ac_delim
_ACEOF


but if I do the same on FreeDOS I get the following output:


am__EXEEXT_FALSE
am__EXEEXTam__EXEEXT_FALSE!$am__EXEEXT_FALSE$ac_delim
am__EXEEXT_TRUE!$am__EXEEXT_TRUE$ac_delim
SHELL!$SHELL$ac_delim
_ACEOF


As can be seen input and output streams get mixed and thus no shell scripts
that depend on redirections of file descriptors and on pipe lines can be run
successfully on FreeDOS.
I have attached 2 small programs in pipe_issue.zip that will reproduce the
situation.  The b.c program does the bash job by redirecting stdout to a file
and then doing some printing to stdout.  Then a pipe is created and the second
program (aka s.c) is spawned.  s.c shall do the job of sed, this means read
from stdin that comes from the read end of the pipe, do some changes to lines
read and write the modified lines to stdout and thus into the file created by
b.c.  The djgpp compiled versions of these programs write the following text
to the redirected stdout on MSDOS:


=========   prolog   =========
first line to stdout
middle line to stdout
last line to stdout
=========   epilog   =========


that then is piped to s.c and modified in this way:


=========   prolog   =========
1st line to stdout
2nd line to stdout
3rd line to stdout
=========   epilog   =========


On all tested FreeDOS versions the absolute identical text get corrupted
in this way:


first line to stdout
middle lin1st line to stdout
2nd line to stdout
3rd line to stdout
=========   epilog   =========


Here again the input and the output streams seems to get mixed some how.
Only for the record, neither my sample programs, nor the bash port, nor djgpp
contain any bugs that are responsable for this behavior.  This is a FreeDOS bug.
I have tried to fix this issue in the kernel, thus I have download 
freedos-svn-r1835-kernel-trunk
and compiled the binaries for 8086 and FAT16.  Nothing else tried and I was
absolutely surprised that the compiled kernel did not failed at all.  The bash
port worked flawlessly with that new kernel, thus the question arises:
why a broken kernel is distributed with a release candidate?  The distributed
kernel version and thus FreeDOS 1.3 is almost useless to run any serious djgpp
applications.  Is this intentional?  If more information is required, please let
me know.

Regards,
Juan M. Guerrero
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <process.h>
#include <errno.h>
#include <libc/fd_props.h>


#define INPUT  "=========   prolog   =========\n" \
               "first line to stdout\n"           \
               "middle line to stdout\n"          \
               "last line to stdout\n"            \
               "=========   epilog   =========\n"

struct pipe_t
{
  int fds[3];
  char *name;
};

static struct pipe_t dos_pipe;

#define READ_END   0
#define WRITE_END  1
#define BACK_UP    2

#define IS_CLOSED(FD)    (dos_pipe.fds[READ_END] == -1 && dos_pipe.fds[WRITE_END] == -1 && dos_pipe.fds[BACK_UP] == -1)
#define SWITCH_MODE(FD)  (dos_pipe.fds[READ_END] != -1 && dos_pipe.fds[WRITE_END] == -1 && dos_pipe.fds[BACK_UP] == (FD))
#define PIPE_FOUND(FD)   (dos_pipe.fds[READ_END] == (FD) || dos_pipe.fds[WRITE_END] == (FD) || (IS_CLOSED((FD)) \
                          || (dos_pipe.fds[READ_END] == -1 && dos_pipe.fds[WRITE_END] == -1)) && dos_pipe.name)


struct stream_t
{
  char *buffer;
  size_t size;
  size_t end;
  size_t start;
};

static struct stream_t buffered_stream;


int
restore_std_fds(int std_fds[3])
{
  int i;
  for (i = 0; i < 3; i++)
  {
    if (std_fds[i] > -1)
    {
      if (dup2(std_fds[i], i) < 0)
      {
        fprintf(stderr, "redirection error: cannot restore %d", i);
        return -1;
      }
      close(std_fds[i]);
      std_fds[i] = -1;
    }
  }
  return 0;
}

int
save_std_fds(int std_fds[3])
{
  int i;
  for (i = 0; i < 3; i++)
  {
    if ((std_fds[i] = fcntl(i, F_DUPFD, 20)) < 0)
    {
      fprintf(stderr, "redirection error: cannot duplicate %d", i);
      return -1;
    }
  }
  return 0;
}

void
remove_pipe(int fd)
{
  if (PIPE_FOUND(fd))
  {
    int orig_errno = errno;

    close(fd);
    if (dos_pipe.fds[READ_END] > -1)
    {
      close(dos_pipe.fds[READ_END]);
      dos_pipe.fds[READ_END] = -1;
    }
    if (dos_pipe.fds[WRITE_END] > -1)
    {
      close(dos_pipe.fds[WRITE_END]);
      dos_pipe.fds[WRITE_END] = -1;
    }
    dos_pipe.fds[BACK_UP] = -1;
    free(dos_pipe.name);
    dos_pipe.name = NULL;

    errno = orig_errno;
  }
}

int
rpl_close(int fd)
{
  if (dos_pipe.fds[READ_END] == fd)
  {
    /* read end closed.  */
    dos_pipe.fds[READ_END] = -1;
  }
  else
  if (dos_pipe.fds[WRITE_END] == fd)
  {
    /* write end closed.  */
    dos_pipe.fds[WRITE_END] = -1;
    if (dos_pipe.fds[READ_END] != -1)
    {
      int ifd, ifd_orig = dos_pipe.fds[READ_END];
      int orig_errno = errno;
      close(fd);

      close(ifd_orig);
      ifd = open(dos_pipe.name, O_RDONLY, 0666);
      if (ifd < 0)
        return -1;

      if (ifd != ifd_orig && ifd_orig > -1)
      {
        int ifd_new = dup2(ifd, ifd_orig);
        close(ifd);
        if (ifd_new != ifd_orig)
          return -1;
      }
      {
        off_t offset = lseek(ifd_orig, 0, SEEK_SET);
offset = offset ;
      }

      errno = orig_errno;
      return 0;
    }
  }
  else
  if (IS_CLOSED(fd))
  {
    /* both pipe ends closed; pipe file removed.  */
    int orig_errno = errno;
/*    remove(dos_pipe.name); */
    free(dos_pipe.name);
    dos_pipe.name = NULL;
    errno = orig_errno;
    return 0;
  }
  else
  if (SWITCH_MODE(fd))
  {
    /* switch from write mode into read mode.  */
    int ifd, ifd_orig = dos_pipe.fds[READ_END];
    int orig_errno = errno;

    close(ifd_orig);
    ifd = open(dos_pipe.name, O_RDONLY, 0666);
    if (ifd < 0)
      return -1;

    if (ifd != ifd_orig && ifd_orig > -1)
    {
      int ifd_new = dup2(ifd, ifd_orig);
      close(ifd);
      if (ifd_new != ifd_orig)
        return -1;
    }
    errno = orig_errno;

    dos_pipe.fds[BACK_UP] = -1;
    return 0;
  }

  return close(fd);
}

int
rpl_pipe(int fds[2])
{
  int ifd, ofd;
  char *tmpdir;
  char *filename;


  tmpdir = "/dev/env/TMPDIR";
  if (access(tmpdir, D_OK))
  {
    tmpdir = "/dev/env/TMP";
    if (access(tmpdir, D_OK))
    {
      tmpdir = "/dev/env/TEMP";
      if (access(tmpdir, D_OK))
      {
        tmpdir = P_tmpdir;
        if (access(tmpdir, D_OK))
          tmpdir = ".";
      }
    }
  }
  filename = malloc(strlen(tmpdir) + sizeof("/ppXXXXXX"));
  if (filename == NULL)
    return -1;
  sprintf(filename, "%s/ppXXXXXX", tmpdir);
  filename = mktemp(filename);
  if (filename == NULL)
    return -1;

  ofd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
  if (ofd < 0)
  {
    free(filename);
    return -1;
  }
  if (ofd < 20)
  {
    int tfd;

    tfd = fcntl(ofd, F_DUPFD, 200);
    close(ofd);
    if (tfd < 0)
    {
      remove(filename);
      free(filename);
      return -1;
    }
    ofd = tfd;
  }

  ifd = open(filename, O_RDONLY, 0666);
  if (ifd < 0)
  {
    free(filename);
    return -1;
  }
  if (ifd < 20)
  {
    int tfd;

    tfd = fcntl(ifd, F_DUPFD, 200);
    close(ifd);
    if (tfd < 0)
    {
      remove(filename);
      free(filename);
      return -1;
    }
    close(ifd);
    ifd = tfd;
  }

  dos_pipe.name = filename;
  dos_pipe.fds[BACK_UP] = ofd;
  fds[0] = dos_pipe.fds[READ_END] = ifd;
  fds[1] = dos_pipe.fds[WRITE_END] = ofd;

  return 0;
}

void echo(const char *text)
{
  printf("%s\n", text);
  fflush(stdout);
}

static FILE *f = NULL;
void dump_std_filenames(void)
{
  static int counter = 0;

  if (!f)
  {
    int tfd = open("./log.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);
    int fd = fcntl(tfd, F_DUPFD, 254);
    if (fd < 0)
      exit(1);

    f = fdopen(fd, "w");
    if (!f)
      exit(2);
  }

  fprintf(f, "%d:\n  0: %s\n  1: %s\n", counter++, __get_fd_name(0), __get_fd_name(1));
  fflush(f);
}

int main(void)
{
  int orig_stdout_fd, orig_stdin_fd;
  int fd, redir_fd;
  int pipe_fds[2], std_fds[3] = {-1, -1, -1};
  char text[] = INPUT;


  //dump_std_filenames();

  /*  A buffered input stream.  Arbitrary.  */
  buffered_stream.buffer = text;
  buffered_stream.size = sizeof(INPUT);
  buffered_stream.start = 0;
  buffered_stream.end = 0;


  /*  Save stdin and stdout for later restauration.  */
  orig_stdin_fd = fcntl(0, F_DUPFD, 20);
  if (orig_stdin_fd < 0)
  {
    fprintf(stderr, "redirection error: cannot duplicate stdin");
    return -1;
  }

  orig_stdout_fd = fcntl(1, F_DUPFD, 20);
  if (orig_stdout_fd < 0)
  {
    fprintf(stderr, "redirection error: cannot duplicate stdout");
    return -2;
  }
  fflush(stdout);
  fpurge(stdout);


  /*  Redirect stdout to a file.  */
  fd = open("redir.txt", O_WRONLY | O_CREAT | O_TRUNC, S_IWUSR);
  redir_fd = fcntl(fd, F_DUPFD, 20);
  if (redir_fd < 0)
  {
    fprintf(stderr, "redirection error: cannot duplicate fd");
    return -3;
  }
  rpl_close(fd);

  if (dup2(redir_fd, 1) < 0)
  {
    fprintf(stderr, "redirection error: cannot redirect stdout");
    return -4;
  }

  if (redir_fd != 1)
    rpl_close(redir_fd);


  /*
   *  Here starts the action.
   *  1: do some printing to stdout.
   */
  while (buffered_stream.buffer[buffered_stream.end] && buffered_stream.buffer[buffered_stream.end] != '\n')
    buffered_stream.end++;
  buffered_stream.buffer[buffered_stream.end] = '\0';

  echo(buffered_stream.buffer + buffered_stream.start);
  fflush(stdout);
  fpurge(stdout);

  buffered_stream.buffer[buffered_stream.end] = '\n';
  buffered_stream.start = ++buffered_stream.end;

  //dump_std_filenames();

  /*  2: create a pipe and assign stdout to the writing end of the pipe.  */
  if (rpl_pipe(pipe_fds) < 0)
  {
    fprintf(stderr, "redirection error: cannot create pipe");
    return -5;
  }

  if (save_std_fds(std_fds) < 0)
    return -6;

  if (dup2(pipe_fds[1], 1) < 0)
  {
    fprintf(stderr, "redirection error: cannot connect stdout to pipe write end");
    return -7;
  }
  if (pipe_fds[1] == 0 || pipe_fds[1] > 1)
    rpl_close(pipe_fds[1]);

  //dump_std_filenames();

  /*  3: print prefix to to stdout.  */
  {
    int i;
    for (i = 0; i < 3; i++, buffered_stream.end++)
      while (buffered_stream.buffer[buffered_stream.end] && buffered_stream.buffer[buffered_stream.end] != '\n')
        buffered_stream.end++;
    buffered_stream.buffer[--buffered_stream.end] = '\0';
  }
  echo(buffered_stream.buffer + buffered_stream.start);
  buffered_stream.buffer[buffered_stream.end] = '\n';
  buffered_stream.start = ++buffered_stream.end;

  /*  4:  restore the std fds.  */
  if (restore_std_fds(std_fds) < 0)
    return -8;

  /*  5:  close the write end of the pipe.  */
  rpl_close(pipe_fds[1]);

  //dump_std_filenames();

  /*  6: save the std file descriptors and assign stdin to the reading end of the pipe.  */
  if (save_std_fds(std_fds) < 0)
    return -9;

  if (dup2(pipe_fds[0], 0) < 0)
  {
    fprintf(stderr, "redirection error: cannot connect stdin to pipe read end");
    return -10;
  }
  if (pipe_fds[0] > 0)
    rpl_close(pipe_fds[0]);

#if 1
  /*  7: change the input data supplied by the pipe according to the rules in s.exe and write the results to stdout.  */
  {
    int status;
    char path[] = "./s.exe";
    char *argv[2];
    argv[0] = path;
    argv[1] = NULL;

    //dump_std_filenames();

    status = spawnv(P_WAIT, path, argv);
  }
#endif

  /*  8: print epilog to to stdout.  */
  while (buffered_stream.buffer[buffered_stream.end] && buffered_stream.buffer[buffered_stream.end] != '\n')
    buffered_stream.end++;
  buffered_stream.buffer[buffered_stream.end] = '\0';

  echo(buffered_stream.buffer + buffered_stream.start);
  fflush(stdout);
  fpurge(stdout);

  buffered_stream.buffer[buffered_stream.end] = '\n';
  buffered_stream.start = buffered_stream.end;

  //dump_std_filenames();

  /*  9: restore original stdin and stdout descriptors.  */
  if (dup2(orig_stdin_fd, 0) < 0)
  {
    fprintf(stderr, "redirection error: cannot restore original stdin");
    return -11;
  }
  rpl_close(orig_stdin_fd);

  if (dup2(orig_stdout_fd, 1) < 0)
  {
    fprintf(stderr, "redirection error: cannot restore original stdout");
    return -12;
  }
  rpl_close(orig_stdout_fd);

  rpl_close(redir_fd);

  echo("bye bye");

  //fclose(f);
  return 0;
}
#include <stdio.h>
#include <libc/fd_props.h>


void dump_std_filenames(void)
{
 const char *stdin_file = __get_fd_name(0);
 const char *stdout_file = __get_fd_name(1);
 const char *stderr_file = __get_fd_name(2);
 printf("0: %s\n1: %s\n2: %s\n", stdin_file, stdout_file, stderr_file);
}

int main(void)
{
  char input_line[1024], output_line[1024];

  while (scanf("%[^\n]\n", input_line) != EOF)
  {
    int src = 0, dst = 0;

    if (input_line[0] == 'f' && input_line[1] == 'i' && input_line[2] == 'r' && input_line[3] == 's' && input_line[4] == 't')
    {
      output_line[0] = '1', output_line[1] = 's', output_line[2] = 't';
      src = 5;
      dst = 3;
    }
    else if (input_line[0] == 'm' && input_line[1] == 'i' && input_line[2] == 'd' && input_line[3] == 'd' && input_line[4] == 'l' && input_line[5] == 'e')
    {
      output_line[0] = '2', output_line[1] = 'n', output_line[2] = 'd';
      src = 6;
      dst = 3;
    }
    else if (input_line[0] == 'l' && input_line[1] == 'a' && input_line[2] == 's' && input_line[3] == 't')
    {
      output_line[0] = '3', output_line[1] = 'r', output_line[2] = 'd';
      src = 4;
      dst = 3;
    }

    while ((output_line[dst++] = input_line[src++]))
      ;
    printf("%s\n", output_line);
  }
  //dump_std_filenames();

  return 0;
}
_______________________________________________
Freedos-devel mailing list
Freedos-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/freedos-devel

Reply via email to