From 2f339225f817921e32f131f2ae163d367f62f564 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Mon, 20 May 2013 19:36:55 +0300 Subject: Move FAKE_FD_VALUE out of gawkapi.h. --- io.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'io.c') diff --git a/io.c b/io.c index 6024c4f9..333d8704 100644 --- a/io.c +++ b/io.c @@ -152,6 +152,10 @@ #define INCREMENT_REC(X) X++ #endif +/* This is for fake directory file descriptors on systems that don't + allow to open() a directory. */ +#define FAKE_FD_VALUE 42 + typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type; /* Several macros to make the code a bit clearer. */ -- cgit v1.2.3 From a25b9b39ac2c49b822328414240061f6d22ddef2 Mon Sep 17 00:00:00 2001 From: "Arnold D. Robbins" Date: Thu, 30 May 2013 21:20:49 +0300 Subject: Minor fix in io.c. --- io.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) (limited to 'io.c') diff --git a/io.c b/io.c index 333d8704..4f682622 100644 --- a/io.c +++ b/io.c @@ -2912,8 +2912,18 @@ iop_finish(IOBUF *iop) if (isdir) iop->errcode = EISDIR; else { + struct stat sbuf; + iop->errcode = EIO; - (void) close(iop->public.fd); + /* + * Extensions can supply values that are not + * INVALID_HANDLE but that are also not real + * file descriptors. So check the fd before + * trying to close it, which avoids errors + * on some operating systems. + */ + if (fstat(iop->public.fd, & sbuf) == 0) + (void) close(iop->public.fd); iop->public.fd = INVALID_HANDLE; } /* -- cgit v1.2.3 From 5482bf19246965d6839fe9df1aec0785f0b1a329 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 1 Jun 2013 13:03:29 +0300 Subject: Support |& on MS-Windows, both for sockets and for pipes. io.c (SHUT_RD) [SD_RECEIVE]: Define to SD_RECEIVE. (SHUT_WR) [SD_SEND]: Define to SD_SEND. (SHUT_RDWR) [SD_BOTH]: Define to SD_BOTH. (FD_TO_SOCKET, closemaybesocket) [!FD_TO_SOCKET]: New macros. (SOCKET_TO_FD, SOCKET) [!SOCKET_TO_FD]: New macros. (PIPES_SIMULATED): Define only for DJGPP. (pipe) [__MINGW32__]: Define to call _pipe, unless PIPES_SIMULATED is defined. (init_io) [HAVE_SOCKETS]: Call init_sockets. (iop_close, socketopen): Call closemaybesocket instead of close. (redirect) [__MINGW32__]: Call wait_any with a non-zero argument. (devopen) [__EMX__ || __MINGW32__]: Don't call stat on network pseudo-filenames. (two_way_open) [HAVE_SOCKETS]: Switch input and output to binary mode if appropriate. (two_way_open) [!PIPES_SIMULATED]: Use the __EMX__ code for MinGW as well. [__MINGW32__] Call spawnl to invoke $ComSpec and pass it a suitably quoted command line. (two_way_open) [__MINGW32__]: Wait only for a specified process ID. If successful, update the exit status of the exited process. Don't use signals that are undefined on MinGW. (two_way_open) [!PIPES_SIMULATED]: Use the __EMX__ code for MinGW as well. (min): Define only if not already defined. (read_with_timeout) [__MINGW32__]: Allow reading from sockets with timeout. (gawk_fclose) [__MINGW32__]: Close the underlying socket as well. getopt.c: Include stdlib.h for MinGW as well. pc/popen.h (SIGKILL) [__MINGW32__]: Define. (kill, quote_cmd): New prototypes. pc/popen.c: Include popen.h and errno.h. (popen, pclose, system): Undefine macros. (WIN32_LEAN_AND_MEAN) [__MINGW32__]: Define and include windows.h. (kill, quote_cmd) [!PIPES_SIMULATED]: New functions. (os_popen): Make the function definition match its prototype exactly. pc/gawkmisc.pc [HAVE_SOCKETS]: Include socket.h and windows.h. (socket, setsockopt, bind, connect, listen, accept, recvfrom) (shutdown): Undefine macros. (os_close_on_exec) [__MINGW32__]: Non-trivial implementation. (init_sockets, socket_to_fd, w32_socket, w32_setsockopt) (w32_bind, w32_connect, w32_listen, w32_accept, valid_socket) (w32_closesocket, w32_recvfrom, w32_shutdown) [HAVE_SOCKETS]: New functions for MinGW, emulate Posix sockets specified by file descriptors. pc/config.h (HAVE_GETADDRINFO, HAVE_SOCKADDR_STORAGE) (HAVE_SOCKETS) [__MINGW32__]: Define. pc/config.sed (HAVE_GETADDRINFO, HAVE_SOCKADDR_STORAGE) (HAVE_SOCKETS) [__MINGW32__]: Define. pc/Makefile.tst (fmtspcl): Announce expected failure only if not built with MPFR. (inetecht, inetdayt): For MinGW, warn about time-outs. (beginfile1, clos1way, getlndir): Announce expected failure only with DJGPP. (exit): Describe the failure on MinGW. (readdir): Explain why test might fail with bad ls.exe. pc/Makefile (mingw32, mingw32-readline, mingw32-mpfr) (mingw32-readline-mpfr): Add -lws2_32 to the link flags. (gawkmisc$O): Depend on socket.h. (io$O): Depend on socket.h and in.h. (popen$O): New dependency. posix/gawkmisc.c (init_sockets): New dummy function. extension/filefuncs.c [_WIN32]: Define WIN32_LEAN_AND_MEAN before including windows.h. extension/readdir.c [__MINGW32__]: Define WIN32_LEAN_AND_MEAN before including windows.h. extension/filefuncs.c [HAVE_GETSYSTEMTIMEASFILETIME]: Define WIN32_LEAN_AND_MEAN before including windows.h. test/clos1way.awk: Don't use features of Posix shells, to allow this test to work on Windows. test/beginfile2.sh: Leave one blank between the left quote and the following slash. Use non-absolute name for a non-existent file. This is to avoid breakage on Windows due to MSYS transformation of Posix style /foo/bar absolute file names. test/beginfile2.ok: Adapt to changes in beginfile2.sh. --- io.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 145 insertions(+), 32 deletions(-) (limited to 'io.c') diff --git a/io.c b/io.c index 4f682622..c8b1f9a1 100644 --- a/io.c +++ b/io.c @@ -119,15 +119,38 @@ #ifdef HAVE_SOCKETS #ifndef SHUT_RD -#define SHUT_RD 0 +# ifdef SD_RECEIVE +# define SHUT_RD SD_RECEIVE +# else +# define SHUT_RD 0 +# endif #endif #ifndef SHUT_WR -#define SHUT_WR 1 +# ifdef SD_SEND +# define SHUT_WR SD_SEND +# else +# define SHUT_WR 1 +# endif #endif #ifndef SHUT_RDWR -#define SHUT_RDWR 2 +# ifdef SD_BOTH +# define SHUT_RDWR SD_BOTH +# else +# define SHUT_RDWR 2 +# endif +#endif + +/* MinGW defines non-trivial macros on pc/socket.h. */ +#ifndef FD_TO_SOCKET +# define FD_TO_SOCKET(fd) (fd) +# define closemaybesocket(fd) close(fd) +#endif + +#ifndef SOCKET_TO_FD +# define SOCKET_TO_FD(s) (s) +# define SOCKET int #endif #endif /* HAVE_SOCKETS */ @@ -140,10 +163,16 @@ #undef TANDEM /* AIX defines this in one of its header files */ #endif -#if defined(__DJGPP__) || defined(__MINGW32__) +#ifdef __DJGPP__ #define PIPES_SIMULATED #endif +#ifdef __MINGW32__ +# ifndef PIPES_SIMULATED +# define pipe(fds) _pipe(fds, 0, O_NOINHERIT) +# endif +#endif + #ifdef HAVE_MPFR /* increment NR or FNR */ #define INCREMENT_REC(X) (do_mpfr && X == (LONG_MAX - 1)) ? \ @@ -265,6 +294,10 @@ init_io() { long tmout; +#ifdef HAVE_SOCKETS + /* Only MinGW has a non-trivial implementation of this. */ + init_sockets(); +#endif /* * N.B.: all these hacks are to minimize the effect * on programs that do not care about timeout. @@ -587,7 +620,7 @@ iop_close(IOBUF *iop) || iop->public.fd == fileno(stderr)) ret = remap_std_file(iop->public.fd); else - ret = close(iop->public.fd); + ret = closemaybesocket(iop->public.fd); } if (ret == -1) @@ -739,7 +772,12 @@ redirect(NODE *redir_exp, int redirtype, int *errflg) */ if ((rp->flag & RED_EOF) != 0 && redirtype == redirect_pipein) { if (rp->pid != -1) +#ifdef __MINGW32__ + /* MinGW cannot wait for any process. */ + wait_any(rp->pid); +#else wait_any(0); +#endif } #endif /* PIPES_SIMULATED */ @@ -1418,7 +1456,7 @@ socketopen(int family, int type, const char *localpname, && (clientsocket_fd = accept(socket_fd, (struct sockaddr *) & remote_addr, & namelen)) >= 0) { - close(socket_fd); + closemaybesocket(socket_fd); socket_fd = clientsocket_fd; break; } @@ -1442,7 +1480,7 @@ socketopen(int family, int type, const char *localpname, nextrres: if (socket_fd != INVALID_HANDLE) - close(socket_fd); + closemaybesocket(socket_fd); socket_fd = INVALID_HANDLE; rres = rres->ai_next; } @@ -1634,8 +1672,10 @@ strictopen: /* On OS/2 and Windows directory access via open() is not permitted. */ struct stat buf; + int l, f; - if (stat(name, & buf) == 0 && S_ISDIR(buf.st_mode)) + if (!inetfile(name, &l, &f) + && stat(name, & buf) == 0 && S_ISDIR(buf.st_mode)) errno = EISDIR; } #endif @@ -1662,7 +1702,9 @@ two_way_open(const char *str, struct redirect *rp) fd = devopen(str, "rw"); if (fd == INVALID_HANDLE) return false; - rp->output.fp = fdopen(fd, "w"); + if ((BINMODE & BINMODE_OUTPUT) != 0) + os_setbinmode(fd, O_BINARY); + rp->output.fp = fdopen(fd, binmode("wb")); if (rp->output.fp == NULL) { close(fd); return false; @@ -1672,6 +1714,8 @@ two_way_open(const char *str, struct redirect *rp) rp->output.gawk_fclose(rp->output.fp, rp->output.opaque); return false; } + if ((BINMODE & BINMODE_INPUT) != 0) + os_setbinmode(newfd, O_BINARY); os_close_on_exec(fd, str, "socket", "to/from"); os_close_on_exec(newfd, str, "socket", "to/from"); rp->iop = iop_alloc(newfd, str, 0); @@ -1929,8 +1973,11 @@ use_pipes: int ptoc[2], ctop[2]; int pid; int save_errno; -#ifdef __EMX__ +#if defined(__EMX__) || defined(__MINGW32__) int save_stdout, save_stdin; +#ifdef __MINGW32__ + char *qcmd = NULL; +#endif #endif if (pipe(ptoc) < 0) @@ -1944,7 +1991,7 @@ use_pipes: return false; } -#ifdef __EMX__ +#if defined(__EMX__) || defined(__MINGW32__) save_stdin = dup(0); /* duplicate stdin */ save_stdout = dup(1); /* duplicate stdout */ @@ -1987,7 +2034,13 @@ use_pipes: os_close_on_exec(save_stdout, str, "pipe", "from"); /* saved stdout of the parent process */ /* stderr does NOT get dup'ed onto child's stdout */ +#ifdef __EMX__ pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", str, NULL); +#else /* __MINGW32__ */ + pid = spawnl(P_NOWAIT, getenv("ComSpec"), "cmd.exe", "/c", + qcmd = quote_cmd(str), NULL); + efree(qcmd); +#endif /* restore stdin and stdout */ close(1); @@ -2015,7 +2068,7 @@ use_pipes: return false; } -#else /* NOT __EMX__ */ +#else /* NOT __EMX__, NOT __MINGW32__ */ if ((pid = fork()) < 0) { save_errno = errno; close(ptoc[0]); close(ptoc[1]); @@ -2042,9 +2095,13 @@ use_pipes: execl("/bin/sh", "sh", "-c", str, NULL); _exit(errno == ENOENT ? 127 : 126); } -#endif /* NOT __EMX__ */ +#endif /* NOT __EMX__, NOT __MINGW32__ */ /* parent */ + if ((BINMODE & BINMODE_INPUT) != 0) + os_setbinmode(ctop[0], O_BINARY); + if ((BINMODE & BINMODE_OUTPUT) != 0) + os_setbinmode(ptoc[1], O_BINARY); rp->pid = pid; rp->iop = iop_alloc(ctop[0], str, 0); find_input_parser(rp->iop); @@ -2061,7 +2118,7 @@ use_pipes: return false; } - rp->output.fp = fdopen(ptoc[1], "w"); + rp->output.fp = fdopen(ptoc[1], binmode("w")); rp->output.mode = "w"; rp->output.name = str; if (rp->output.fp == NULL) { @@ -2078,7 +2135,7 @@ use_pipes: else find_output_wrapper(& rp->output); -#ifndef __EMX__ +#if !defined(__EMX__) && !defined(__MINGW32__) os_close_on_exec(ctop[0], str, "pipe", "from"); os_close_on_exec(ptoc[1], str, "pipe", "from"); @@ -2110,15 +2167,31 @@ wait_any(int interesting) /* pid of interest, if any */ int status = 0; struct redirect *redp; - hstat = signal(SIGHUP, SIG_IGN); istat = signal(SIGINT, SIG_IGN); +#ifdef __MINGW32__ + if (interesting < 0) { + status = -1; + pid = -1; + } + else + pid = _cwait(& status, interesting, 0); + if (pid == interesting && pid > 0) { + for (redp = red_head; redp != NULL; redp = redp->next) + if (interesting == redp->pid) { + redp->pid = -1; + redp->status = status; + break; + } + } +#else + hstat = signal(SIGHUP, SIG_IGN); qstat = signal(SIGQUIT, SIG_IGN); for (;;) { -#ifdef HAVE_SYS_WAIT_H /* POSIX compatible sys/wait.h */ +# ifdef HAVE_SYS_WAIT_H /* POSIX compatible sys/wait.h */ pid = wait(& status); -#else +# else pid = wait((union wait *) & status); -#endif +# endif if (interesting && pid == interesting) { break; } else if (pid != -1) { @@ -2133,8 +2206,9 @@ wait_any(int interesting) /* pid of interest, if any */ break; } signal(SIGHUP, hstat); - signal(SIGINT, istat); signal(SIGQUIT, qstat); +#endif + signal(SIGINT, istat); return status; } @@ -2145,8 +2219,11 @@ gawk_popen(const char *cmd, struct redirect *rp) { int p[2]; int pid; -#ifdef __EMX__ +#if defined(__EMX__) || defined(__MINGW32__) int save_stdout; +#ifdef __MINGW32__ + char *qcmd = NULL; +#endif #endif /* @@ -2160,7 +2237,7 @@ gawk_popen(const char *cmd, struct redirect *rp) if (pipe(p) < 0) fatal(_("cannot open pipe `%s' (%s)"), cmd, strerror(errno)); -#ifdef __EMX__ +#if defined(__EMX__) || defined(__MINGW32__) rp->iop = NULL; save_stdout = dup(1); /* save stdout */ if (save_stdout == -1) { @@ -2182,8 +2259,14 @@ gawk_popen(const char *cmd, struct redirect *rp) os_close_on_exec(p[0], cmd, "pipe", "from"); /* pipe output: input of the parent process */ os_close_on_exec(save_stdout, cmd, "pipe", "from"); /* saved stdout of the parent process */ - + +#ifdef __EMX__ pid = spawnl(P_NOWAIT, "/bin/sh", "sh", "-c", cmd, NULL); +#else /* __MINGW32__ */ + pid = spawnl(P_NOWAIT, getenv("ComSpec"), "cmd.exe", "/c", + qcmd = quote_cmd(cmd), NULL); + efree(qcmd); +#endif /* restore stdout */ close(1); @@ -2193,7 +2276,7 @@ gawk_popen(const char *cmd, struct redirect *rp) } close(save_stdout); -#else /* NOT __EMX__ */ +#else /* NOT __EMX__, NOT __MINGW32__ */ if ((pid = fork()) == 0) { if (close(1) == -1) fatal(_("close of stdout in child failed (%s)"), @@ -2205,20 +2288,22 @@ gawk_popen(const char *cmd, struct redirect *rp) execl("/bin/sh", "sh", "-c", cmd, NULL); _exit(errno == ENOENT ? 127 : 126); } -#endif /* NOT __EMX__ */ +#endif /* NOT __EMX__, NOT __MINGW32__ */ if (pid == -1) { close(p[0]); close(p[1]); fatal(_("cannot create child process for `%s' (fork: %s)"), cmd, strerror(errno)); } rp->pid = pid; -#ifndef __EMX__ +#if !defined(__EMX__) && !defined(__MINGW32__) if (close(p[1]) == -1) { close(p[0]); fatal(_("close of pipe failed (%s)"), strerror(errno)); } #endif os_close_on_exec(p[0], cmd, "pipe", "from"); + if ((BINMODE & BINMODE_INPUT) != 0) + os_setbinmode(p[0], O_BINARY); rp->iop = iop_alloc(p[0], cmd, 0); find_input_parser(rp->iop); iop_finish(rp->iop); @@ -3403,7 +3488,9 @@ get_a_record(char **out, /* pointer to pointer to data */ recm.rt_start = iop->off + recm.len; /* read more data, break if EOF */ +#ifndef min #define min(x, y) (x < y ? x : y) +#endif /* subtract one in read count to leave room for sentinel */ room_left = iop->end - iop->dataend - 1; amt_to_read = min(iop->readsize, room_left); @@ -3741,21 +3828,38 @@ get_read_timeout(IOBUF *iop) static ssize_t read_with_timeout(int fd, char *buf, size_t size) { -#if ! defined(__MINGW32__) && ! defined(VMS) +#if ! defined(VMS) fd_set readfds; struct timeval tv; +#ifdef __MINGW32__ + /* + * Only sockets can be read with a timeout. Also, the FD_* + * macros work on SOCKET type, not on int file descriptors. + */ + SOCKET s = valid_socket(fd); + + if (!s) + return read(fd, buf, size); +#else + int s = fd; +#endif tv.tv_sec = read_timeout / 1000; tv.tv_usec = 1000 * (read_timeout - 1000 * tv.tv_sec); FD_ZERO(& readfds); - FD_SET(fd, & readfds); + FD_SET(s, & readfds); errno = 0; + /* + * Note: the 1st arg of 'select' is ignored on MS-Windows, so + * it's not a mistake to pass fd+1 there, although we use + * sockets, not file descriptors. + */ if (select(fd + 1, & readfds, NULL, NULL, & tv) < 0) return -1; - if (FD_ISSET(fd, & readfds)) + if (FD_ISSET(s, & readfds)) return read(fd, buf, size); /* else timed out */ @@ -3767,9 +3871,9 @@ read_with_timeout(int fd, char *buf, size_t size) errno = EAGAIN; #endif return -1; -#else /* __MINGW32__ || VMS */ +#else /* VMS */ return read(fd, buf, size); -#endif /* __MINGW32__ || VMS */ +#endif /* VMS */ } /* @@ -3805,9 +3909,18 @@ gawk_ferror(FILE *fp, void *opaque) static int gawk_fclose(FILE *fp, void *opaque) { + int result; +#ifdef __MINGW32__ + SOCKET s = valid_socket (fileno(fp)); +#endif (void) opaque; - return fclose(fp); + result = fclose(fp); +#ifdef __MINGW32__ + if (s && closesocket(s) == SOCKET_ERROR) + result = -1; +#endif + return result; } -- cgit v1.2.3