/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
#include "util.h"
#include "loop.h"
#include "error.h"
#include <poll.h>
#include <sys/termios.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "stdio.h"
#ifndef INFTIM
#define INFTIM -1
#endif
#ifdef __APPLE__
int loop(
int master_fd) {
ssize_t n;
char buf[BUFSIZ];
int select_result;
fd_set read_set;
for (;;) {
FD_ZERO(&read_set);
FD_SET(STDIN_FILENO, &read_set);
FD_SET(master_fd, &read_set);
select_result = select(master_fd + 1, &read_set, NULL, NULL, NULL);
// interrupted select is ignored - see CR 7086177
if (select_result == -1 && errno == EINTR) {
continue;
}
if (select_result == -1) {
err_sys(
"poll failed\n");
}
if (FD_ISSET(STDIN_FILENO, &read_set)) {
if ((n = read(STDIN_FILENO, buf, BUFSIZ)) == -1) {
err_sys(
"read from stdin failed\n");
}
if (n == 0) {
break;
}
if (write(master_fd, buf, n) == -1) {
err_sys(
"write to master failed\n");
}
}
if (FD_ISSET(master_fd, &read_set)) {
if ((n = read(master_fd, buf, BUFSIZ)) == -1) {
err_sys(
"read from master failed\n");
}
if (n == 0) {
break;
}
if (write(STDOUT_FILENO, buf, n) == -1) {
err_sys(
"write to stdout failed\n");
exit(1);
}
}
}
return 0;
}
#else
#define FRAGSIZ 1000
int loop(
int master_fd) {
ssize_t n;
char buf[FRAGSIZ];
struct pollfd fds[2];
struct buffer to_master;
to_master.offset = 0;
to_master.length = 0;
fds[0].fd = STDIN_FILENO;
fds[0].events = POLLIN;
fds[0].revents = 0;
fds[1].fd = master_fd;
fds[1].events = POLLIN;
fds[1].revents = 0;
int poll_result;
for (;;) {
poll_result = poll((
struct pollfd*) & fds, 2, INFTIM);
// interrupted poll is ignored - see CR 7086177
if (poll_result == -1 && errno == EINTR) {
continue;
}
if (poll_result == -1) {
err_sys(
"poll() failed in main_loop");
}
if (fds[1].revents & POLLIN) {
if ((n = read(master_fd, buf, FRAGSIZ)) == -1) {
#ifdef __CYGWIN__
// On Windows master_fd is invalid here
// (bug #252202)
close(master_fd);
return 0;
#else
err_sys(
"read from master failed\n");
#endif
}
if (n == 0) {
break;
}
if (writen(STDOUT_FILENO, buf, n) == -1) {
err_sys(
"write to stdout failed\n");
}
}
if (to_master.offset != to_master.length) {
int nwritten = writen_no_block(master_fd, &to_master);
if (nwritten == -1) {
err_sys(
"write to master failed\n");
}
}
else if (fds[0].revents & POLLIN) {
if ((n = read(STDIN_FILENO, to_master.buf, FRAGSIZ)) == -1) {
err_sys(
"read from stdin failed");
}
if (n == 0) {
#ifdef __CYGWIN__
// On Windows when calling process is killed,
// POLLIN flag is set, not POLLHUP.
// So behave as if we have received POLLHUP in this case...
close(master_fd);
return 1;
#endif
break;
}
to_master.offset = 0;
to_master.length = n;
int nwritten = writen_no_block(master_fd, &to_master);
if (nwritten == -1) {
err_sys(
"write to master failed\n");
}
}
if (fds[1].revents & POLLHUP) {
break;
}
if (fds[0].revents & POLLHUP) {
// STDIN END is broken...
// Cannot just break at this point as 'child' process still alive.
// [will hung on waitpid later.. ]
// So will close the MASTER END => this causes a hangup to occur on
// the other end of the pipe.
// no data is drained in this case...
close(master_fd);
return 1;
}
}
return 0;
}
#endif