Removed utf-8 from readme.
/*
stdin mix - a mixer/multiplexer for stdin to processes
Copyright (C) 2007 LluĂs Batlle i Rossell
Please find the license in the provided COPYING file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "main.h"
static const char version[] = "0.9.1";
static int max(int a, int b)
{
if (a > b)
return a;
return b;
}
static int fork_app(int *opipe /*[3]*/, char * const command[])
{
int p_input[2]; /* from mpg321 to us */
int p_output[2]; /* from us to mpg321 */
int p_error[2]; /* from mpg321 to us, its stderr */
int pid;
int res;
pipe(p_input);
pipe(p_output);
pipe(p_error);
opipe[0] = p_input[0]; /* For us to read */
opipe[1] = p_output[1]; /* For us to write */
opipe[2] = p_error[0]; /* For us to read */
pid = fork();
switch(pid)
{
case 0: /* child */
close(p_input[0]);
res = dup2(p_input[1], 1);
if (res == -1) perror("Dup2 1");
close(p_error[0]);
res = dup2(p_error[1], 2);
if (res == -1) perror("Dup2 2");
close(p_input[1]);
close(p_error[1]);
close(p_output[1]);
res = dup2(p_output[0], 0);
if (res == -1) perror("Dup2 3");
close(p_output[0]);
execvp(command[0], command);
error("Cannot execlp %s", command[0]);
case -1:
error("Failed fork");
default: /* parent */
close(p_input[1]);
close(p_error[1]);
close(p_output[0]);
}
return pid;
}
static int forward_app_data(int in, int out)
{
char buf[100];
int res;
res = read(in, buf, sizeof(buf));
if (res > 0)
write(out, buf, res);
return res;
}
static void loop(const int *child_pipe, int lsocket)
{
char buf[100];
fd_set read_set;
int child_read, child_write, child_read_error;
int maxfd;
int opened_socket;
int stdin_opened;
int child_read_opened, child_read_error_opened;
int res;
child_read = child_pipe[0];
child_read_error = child_pipe[2];
child_write = child_pipe[1];
stdin_opened = 1;
opened_socket = -1; /* no socket opened */
child_read_opened = 1;
child_read_error_opened = 1;
do
{
FD_ZERO(&read_set);
maxfd = 0;
if (stdin_opened)
FD_SET(0, &read_set);
if (child_read_opened)
{
FD_SET(child_read, &read_set);
maxfd = max(maxfd, child_read);
}
if (child_read_error_opened)
{
FD_SET(child_read_error, &read_set);
maxfd = max(maxfd, child_read_error);
}
if (opened_socket >= 0)
{
FD_SET(opened_socket, &read_set);
maxfd = max(maxfd, opened_socket);
}
else
{
/* We only accept if we don't have any
* connetion opened. */
FD_SET(lsocket, &read_set);
maxfd = max(maxfd, lsocket);
}
/* Will block */
res = select(maxfd + 1, &read_set, 0, 0, 0);
if (res == -1)
{
if (errno == EINTR)
continue;
else
error("Error in select()");
}
if (child_read_opened && FD_ISSET(child_read, &read_set))
{
res = forward_app_data(child_read, 1);
if (res == 0)
{
close(1);
child_read_opened = 0;
if (child_read_error_opened == 0)
break;
}
}
if (child_read_error_opened && FD_ISSET(child_read_error, &read_set))
{
res = forward_app_data(child_read_error, 2);
if (res == 0)
{
close(2);
child_read_error_opened = 0;
if (child_read_opened == 0)
break;
}
}
if (FD_ISSET(0, &read_set))
{
res = forward_app_data(0, child_write);
if (res == 0)
{
close(child_write);
stdin_opened = 0;
}
}
if (opened_socket >= 0 && FD_ISSET(opened_socket, &read_set))
{
res = forward_app_data(opened_socket, child_write);
if (res == 0)
{
close(opened_socket);
opened_socket = -1; /* no socket open */
}
}
if (opened_socket == -1 && FD_ISSET(lsocket, &read_set))
{
opened_socket = accept_connection(lsocket);
}
} while(1);
}
static int server(int argn, char * const argv[])
{
int p[3];
int lsocket;
int child;
child = fork_app(p, &argv[1]);
install_signal_forwarders(child);
lsocket = serve_socket();
loop(p, lsocket);
remove_socket(lsocket);
return 0;
}
static int client()
{
int cs;
int res;
fd_set read_set;
int maxfd;
cs = connect_socket();
do
{
FD_ZERO(&read_set);
FD_SET(cs, &read_set); /* For reading other side's close() */
maxfd = cs;
FD_SET(0, &read_set); /* stdin */
maxfd = max(maxfd, cs);
res = select(maxfd + 1, &read_set, 0, 0, 0);
if (res == -1)
{
if (errno == EINTR)
continue;
else
error("Error in select()");
}
if (FD_ISSET(cs, &read_set))
{
/* assuming close() on the other side, even
* without read(). */
break;
}
if (FD_ISSET(0, &read_set))
{
res = forward_app_data(0, cs);
if (res == 0) /* EOF */
break;
}
} while (1);
close(cs);
return 0;
}
static int showhelp(const char *pname)
{
printf("sdtdin-mix v%s - Copyright (C) 2007 Lluis Batlle i Rossell\n",
version);
printf("usage: %s [appcommand] [param1] [param2] ...\n", pname);
printf(" If you give _appcommand_, it starts the application and\n");
printf(" a stdin server on $SM_SOCKET or /tmp/socket-sm.UID.\n");
printf(" If not given, it starts a stdin client for the same socket.\n");
return 0;
}
int main(int argn, char * const * argv)
{
int res;
if (argn > 1 && strcmp(argv[1], "-h") == 0)
res = showhelp(argv[0]);
else if (argn > 1)
res = server(argn, argv);
else
res = client();
return res;
}