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