[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[GNUnet-SVN] r29924 - msh/src
From: |
gnunet |
Subject: |
[GNUnet-SVN] r29924 - msh/src |
Date: |
Mon, 7 Oct 2013 16:19:52 +0200 |
Author: harsha
Date: 2013-10-07 16:19:52 +0200 (Mon, 07 Oct 2013)
New Revision: 29924
Modified:
msh/src/Makefile.am
msh/src/msh_waiter.c
msh/src/test_pty.c
Log:
- exec child with pty
Modified: msh/src/Makefile.am
===================================================================
--- msh/src/Makefile.am 2013-10-07 13:58:09 UTC (rev 29923)
+++ msh/src/Makefile.am 2013-10-07 14:19:52 UTC (rev 29924)
@@ -31,7 +31,7 @@
launch_SOURCES = launch.c
launch_LDADD = -lgnunetutil
-test_pty_SOURCES = test_pty.c
+test_pty_SOURCES = test_pty.c mtyes.h ttymodes.h ttymodes.c
test_pty_LDADD = -lgnunetutil
msh_waiter_SOURCES = msh_waiter.c mtypes.h ttymodes.h ttymodes.c
Modified: msh/src/msh_waiter.c
===================================================================
--- msh/src/msh_waiter.c 2013-10-07 13:58:09 UTC (rev 29923)
+++ msh/src/msh_waiter.c 2013-10-07 14:19:52 UTC (rev 29924)
@@ -285,8 +285,7 @@
tmsg->ispeed = htonl (speed_to_baud (cfgetispeed (&tio)));
tmsg->nsettings = htons (count);
- ts = &tmsg->nsettings;
- ts++;
+ ts = &tmsg[1];
#define TTYCHAR(NAME,OP) \
*(ts++) = htons (OP); \
*(ts++) = htons (tio.c_cc[NAME]);
Modified: msh/src/test_pty.c
===================================================================
--- msh/src/test_pty.c 2013-10-07 13:58:09 UTC (rev 29923)
+++ msh/src/test_pty.c 2013-10-07 14:19:52 UTC (rev 29924)
@@ -1,6 +1,7 @@
#include "common.h"
#include <gnunet/gnunet_util_lib.h>
#include <termios.h>
+#include "mtypes.h"
/****************************************************************************/
/* Implemented after http://rachid.koucha.free.fr/tech_corner/pty_pdip.html */
@@ -13,12 +14,24 @@
#define LOG_ERROR(...) LOG(GNUNET_ERROR_TYPE_ERROR, __VA_ARGS__)
+#define TIMEOUT(secs) \
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, secs)
+
+#define DEFAULT_TIMEOUT TIMEOUT(30)
+
+#define BUF_SIZE 512
+
/**
* Task to kill the child
*/
-static GNUNET_SCHEDULER_TaskIdentifier child_death_task_id;
+static GNUNET_SCHEDULER_TaskIdentifier child_death_task;
/**
+ * Task to read output from child
+ */
+static GNUNET_SCHEDULER_TaskIdentifier read_child_task;
+
+/**
* Pipe used to communicate shutdown via signal.
*/
static struct GNUNET_DISK_PipeHandle *sigpipe;
@@ -26,39 +39,162 @@
static struct GNUNET_DISK_FileHandle *chld_io;
static struct GNUNET_DISK_FileHandle *our_in;
+static struct GNUNET_CONNECTION_Handle *conn;
+
+static struct GNUNET_CONNECTION_TransmitHandle *tx;
+
static char **chld_argv;
+static char *cp;
+static struct termios tio;
+static struct winsize ws;
+static int in_receive;
+
+static char buf[BUF_SIZE];
+static size_t buf_off;
+
+
+/**
+ * Function to copy NULL terminated list of arguments
+ *
+ * @param argv the NULL terminated list of arguments. Cannot be NULL.
+ * @return the copied NULL terminated arguments
+ */
+static char **
+copy_argv (char *const *argv)
+{
+ char **argv_dup;
+ unsigned int argp;
+
+ GNUNET_assert (NULL != argv);
+ for (argp = 0; NULL != argv[argp]; argp++) ;
+ argv_dup = GNUNET_malloc (sizeof (char *) * (argp + 1));
+ for (argp = 0; NULL != argv[argp]; argp++)
+ argv_dup[argp] = strdup (argv[argp]);
+ return argv_dup;
+}
+
+
+/**
+ * Frees the given NULL terminated arguments
+ *
+ * @param argv the NULL terminated list of arguments
+ */
static void
-chld_read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+free_argv (char **argv)
{
- char buf[512];
+ unsigned int argp;
+
+ for (argp = 0; NULL != argv[argp]; argp++)
+ GNUNET_free (argv[argp]);
+ GNUNET_free (argv);
+}
+
+
+/**
+ * shutdown task
+ */
+static void
+do_shutdown (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (NULL != chld_argv)
+ {
+ free_argv (chld_argv);
+ chld_argv = NULL;
+ }
+ if (NULL != conn)
+ {
+ if (in_receive)
+ GNUNET_CONNECTION_receive_cancel (conn);
+ if (NULL != tx)
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (tx);
+ GNUNET_CONNECTION_destroy (conn);
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != child_death_task)
+ {
+ GNUNET_SCHEDULER_cancel (child_death_task);
+ child_death_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != chld_io)
+ GNUNET_DISK_file_close (chld_io);
+}
+
+
+/**
+ * Read the child processes output and send it to over network connection to
waiter
+ */
+static void
+read_child (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Function called to notify a client about the connection
+ * begin ready to queue more data. "buf" will be
+ * NULL and "size" zero if the connection was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param netbuf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+do_tx (void *cls, size_t size, void *netbuf)
+{
+ tx = NULL;
+ if ((NULL == buf) || (0 == size))
+ {
+ LOG_ERROR ("Failure in connectivity\n");
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GNUNET_assert (buf_off <= size);
+ (void) memcpy (netbuf, buf, buf_off);
+ buf_off = 0;
+ if (GNUNET_SCHEDULER_NO_TASK != read_child_task)
+ return;
+ read_child_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
+ &read_child, NULL);
+}
+
+
+/**
+ * Read the child processes output and send it to over network connection to
waiter
+ */
+static void
+read_child (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
ssize_t rsize;
- ssize_t wsize;
+ read_child_task = GNUNET_SCHEDULER_NO_TASK;
if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
return;
- rsize = GNUNET_DISK_file_read (chld_io, buf, sizeof (buf));
+ if (BUF_SIZE == buf_off)
+ {
+ GNUNET_assert (NULL != tx);
+ return;
+ }
+ rsize = GNUNET_DISK_file_read (chld_io, buf + buf_off, BUF_SIZE - buf_off);
if (rsize <= 0)
{
LOG_DEBUG ("Child stdout closed\n");
return;
}
- wsize = 0;
- while ((0 < rsize) &&
- (GNUNET_SYSERR != (wsize = write (1, ((void *) buf) + wsize, rsize)))
)
- {
- rsize -= wsize;
- }
- if (0 != rsize)
- {
- GNUNET_break (0);
+ buf_off += rsize;
+ if (NULL != tx)
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (tx);
+ tx = GNUNET_CONNECTION_notify_transmit_ready (conn, buf_off, DEFAULT_TIMEOUT,
+ &do_tx, NULL);
+ if (BUF_SIZE == buf_off)
return;
- }
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
- &chld_read_task, NULL);
+ read_child_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
+ &read_child, NULL);
}
+
/**
* Task triggered whenever we receive a SIGCHLD (child
* process died).
@@ -67,7 +203,7 @@
* @param tc context
*/
static void
-child_death_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+child_died (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
{
const struct GNUNET_DISK_FileHandle *pr;
ssize_t rsize;
@@ -75,88 +211,436 @@
char c[16];
pr = GNUNET_DISK_pipe_handle (sigpipe, GNUNET_DISK_PIPE_END_READ);
- child_death_task_id = GNUNET_SCHEDULER_NO_TASK;
+ child_death_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
if (0 == (tc->reason & GNUNET_SCHEDULER_REASON_READ_READY))
{
- child_death_task_id =
+ child_death_task =
GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
- pr, &child_death_task, NULL);
+ pr, &child_died, NULL);
return;
}
/* consume the signal */
GNUNET_break (0 < GNUNET_DISK_file_read (pr, &c, sizeof (c)));
LOG_DEBUG ("Child died\n");
GNUNET_SCHEDULER_shutdown ();
- /* read any of the left over IO */
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
- &chld_read_task, NULL);
+ /* FIXME: read any of the left over output from child? */
}
+
+/**
+ * Signal handler called for SIGCHLD.
+ */
static void
-read_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+sighandler_child_death ()
{
- char buf[512];
- ssize_t rsize;
- ssize_t wsize;
+ static char c;
+ int old_errno = errno; /* back-up errno */
- if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
- return;
- rsize = GNUNET_DISK_file_read (our_in, buf, sizeof (buf));
- if (GNUNET_SYSERR == rsize)
- return;
- wsize = 0;
- while ((0 < rsize) &&
- (GNUNET_SYSERR != (wsize = GNUNET_DISK_file_write
- (chld_io, ((void *) buf) + wsize,
- rsize))) )
+ GNUNET_break (1 ==
+ GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
+ (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
+ &c, sizeof (c)));
+ errno = old_errno; /* restore errno */
+}
+
+
+/**
+ * Configure the terminal for the child
+ */
+static int
+parse_term_mode (const struct MSH_MSG_PtyMode *msg)
+{
+ uint16_t *params;
+ unsigned int cnt;
+ unsigned int ns;
+ uint16_t msize;
+ size_t expected;
+ speed_t ospeed;
+ speed_t ispeed;
+
+ msize = ntohs (msg->header.size);
+ ns = ntohs (msg->nsettings);
+ expected = (sizeof (struct MSH_MSG_PtyMode) + (sizeof (uint16_t) * ns * 2));
+ if (msize < expected)
{
- rsize -= wsize;
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
}
- if (0 != rsize)
+#define PARSE_WIN_SIZE(field) \
+ ws.field = ntohs (msg->field);
+ PARSE_WIN_SIZE (ws_row);
+ PARSE_WIN_SIZE (ws_col);
+ PARSE_WIN_SIZE (ws_xpixel);
+ PARSE_WIN_SIZE (ws_ypixel);
+#undef PARSE_WIN_SIZE
+ ospeed = baud_to_speed (ntohl (msg->ospeed));
+ ispeed = baud_to_speed (ntohl (msg->ispeed));
+ if (0 != cfsetospeed (&tio, ospeed))
{
GNUNET_break (0);
- return;
+ return GNUNET_SYSERR;
}
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, our_in,
- &read_task, NULL);
+ if (0 != cfsetispeed (&tio, ispeed))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+ params = (uint16_t *) &msg[1];
+ for (cnt = 0; cnt < ns; cnt++)
+ {
+ switch (ntohs (params[2 * cnt]))
+ {
+#define TTYCHAR(NAME,OP) \
+ case OP: \
+ tio.c_cc[NAME] = ntohs (params[(2 * cnt)+1]); \
+ break;
+#define TTYMODE(NAME, FIELD, OP) \
+ case OP: \
+ if (1 == ntohs (params[(2 * cnt)+1])) \
+ tio.FIELD |= NAME; \
+ break;
+#include "ttymodes.h"
+#undef TTYCHAR
+#undef TTYMODE
+
+ default:
+ GNUNET_assert (0);
+ }
+ }
+ if (0 == (msize - expected))
+ return GNUNET_OK;
+ cp = ((void *) msg) + expected;
+ if ('\0' != cp[(msize - expected) - 1])
+ {
+ GNUNET_break (0);
+ cp = NULL;
+ return GNUNET_OK;
+ }
+ cp = GNUNET_strdup (cp);
+ return GNUNET_OK;
}
/**
- * Signal handler called for SIGCHLD.
+ * Create pty, fork, setup the tty modes and exec the given binary
*/
+static int
+spawn_child ()
+{
+ const char *fn;
+ int master;
+ int ret;
+
+ master = posix_openpt (O_RDWR);
+ if (-1 == master)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "posix_openpt");
+ goto err_ret;
+ }
+ if (-1 == grantpt (master))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "grantpt");
+ goto err_ret;
+ }
+ if (-1 == unlockpt (master))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "unlockpt");
+ goto err_ret;
+ }
+ if (NULL == (fn = ptsname (master)))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ptsname");
+ goto err_ret;
+ }
+ ret = fork();
+ if (-1 == ret)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "fork");
+ goto err_ret;
+ }
+ if (0 != ret)
+ {
+ chld_io = GNUNET_DISK_get_handle_from_int_fd (master);
+ read_child_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
+ &read_child, NULL);
+ return GNUNET_OK;
+ }
+ /* child process */
+ {
+ int slave;
+
+ close (master);
+ close (0);
+ close (1);
+ close (2);
+ slave = open (fn, O_RDWR);
+ if (-1 == slave)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "open");
+ _exit (1);
+ }
+ if (-1 == tcsetattr (slave, TCSANOW, &tio))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "tcsetattr");
+ _exit (1);
+ }
+ if (-1 == ioctl (slave, TIOCSWINSZ, &ws))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "ioctl");
+ _exit (1);
+ }
+ if ( (-1 == dup2 (slave, 0)) ||
+ (-1 == dup2 (slave, 1)) ||
+ (-1 == dup2 (slave, 2)) )
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "dup");
+ _exit (1);
+ }
+ if (-1 == setsid ())
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsid");
+ _exit (1);
+ }
+ if (-1 == execvp (chld_argv[0], chld_argv))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "execvp");
+ _exit (1);
+ }
+ }
+
+ err_ret:
+ GNUNET_SCHEDULER_shutdown ();
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Callback function for data received from the network. Note that
+ * both "available" and "err" would be 0 if the read simply timed out.
+ *
+ * @param cls closure
+ * @param buf pointer to received data
+ * @param available number of bytes availabe in "buf",
+ * possibly 0 (on errors)
+ * @param addr address of the sender
+ * @param addrlen size of addr
+ * @param errCode value of errno (on errors receiving)
+ */
static void
-sighandler_child_death ()
+net_receive (void *cls, const void *buf, size_t available,
+ const struct sockaddr * addr, socklen_t addrlen, int errCode)
{
- static char c;
- int old_errno = errno; /* back-up errno */
+ static enum {
+ STATE_HEADER = 0,
+ STATE_MSG,
+ STATE_FORWARD
+ } state;
+ static struct MSH_MSG_PtyMode *msg;
+ static size_t rb;
+ struct GNUNET_TIME_Relative timeout;
+ size_t rsize;
+
+ in_receive = 0;
+ if (0 == available)
+ {
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ switch (state)
+ {
+ case STATE_HEADER:
+ {
+ static struct GNUNET_MessageHeader hdr;
+ uint16_t msize;
- GNUNET_break (1 ==
- GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle
- (sigpipe, GNUNET_DISK_PIPE_END_WRITE),
- &c, sizeof (c)));
- errno = old_errno; /* restore errno */
+ GNUNET_assert (available <= sizeof (hdr));
+ memcpy (((void *) &hdr) + rb, buf, available);
+ rb += available;
+ timeout = DEFAULT_TIMEOUT;
+ rsize = sizeof (hdr) - rb;
+ if (0 != rsize)
+ goto read_again;
+ if (MSH_MTYPE_PTY_MODE != ntohs (hdr.type))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ msize = ntohs (hdr.size);
+ msg = GNUNET_malloc (msize);
+ memcpy (msg, &hdr, sizeof (hdr));
+ rsize = msize - sizeof (hdr);
+ state = STATE_MSG;
+ goto read_again;
+ }
+ case STATE_MSG:
+ {
+ uint16_t msize;
+
+ msize = ntohs (msg->header.size);
+ GNUNET_assert (available <= (msize - rb));
+ memcpy (((void *) msg) + rb, buf, available);
+ rb += available;
+ timeout = DEFAULT_TIMEOUT;
+ rsize = msize - rb;
+ if (0 != rsize)
+ goto read_again;
+ parse_term_mode (msg);
+ GNUNET_free (msg);
+ msg = NULL;
+ spawn_child ();
+ state = STATE_FORWARD;
+ }
+ break;
+ case STATE_FORWARD:
+ /* receive from net and write to child pty */
+ {
+ size_t wb;
+ ssize_t ret;
+
+ wb = 0;
+ do {
+ ret = GNUNET_DISK_file_write (chld_io, buf + wb, available - wb);
+ if (GNUNET_SYSERR == ret)
+ {
+ GNUNET_break (0);
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ wb += ret;
+ } while (wb < available);
+ }
+ break;
+ }
+ rsize = BUF_SIZE;
+ timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+
+ read_again:
+ GNUNET_CONNECTION_receive (conn, rsize, timeout, &net_receive, NULL);
+ in_receive = 1;
}
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be
NULL!)
+ * @param c configuration
+ */
static void
-run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+run (void *cls,
+ char *const *args,
+ const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *c)
{
- child_death_task_id =
+ unsigned int argc;
+ const char *hostname;
+ const char *portstr;
+ struct sockaddr *addr;
+ struct addrinfo *res;
+ struct addrinfo hints;
+ int af_family;
+ socklen_t addrlen;
+ int ret;
+
+ argc = 0;
+ hostname = args[argc++];
+ if (NULL == hostname)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ portstr = args[argc++];
+ if (NULL == portstr)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (NULL == args[argc])
+ {
+ GNUNET_break (0);
+ return;
+ }
+ (void) memset (&hints, 0, sizeof (hints));
+ hints.ai_flags = AI_NUMERICSERV;
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ ret = getaddrinfo (hostname, portstr, &hints, &res);
+ if (0 != ret)
+ {
+ LOG_ERROR ("getaddrinfo() failed: %s\n", gai_strerror (ret));
+ return;
+ }
+ if (NULL == res)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ addrlen = res[0].ai_addrlen;
+ addr = GNUNET_malloc (addrlen);
+ memcpy (addr, res[0].ai_addr, addrlen);
+ af_family = res[0].ai_family;
+ freeaddrinfo (res);
+ conn = GNUNET_CONNECTION_create_from_sockaddr (af_family, addr, addrlen);
+ GNUNET_free (addr);
+ if (NULL == conn)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_CONNECTION_receive (conn, sizeof (struct GNUNET_MessageHeader),
+ DEFAULT_TIMEOUT, &net_receive, NULL);
+ in_receive = 1;
+ child_death_task =
GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
GNUNET_DISK_pipe_handle (sigpipe,
GNUNET_DISK_PIPE_END_READ),
- &child_death_task, NULL);
+ &child_died, NULL);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_shutdown, NULL);
+ chld_argv = copy_argv (&args[argc]);
+ return;
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, our_in,
- &read_task, NULL);
- GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, chld_io,
- &chld_read_task, NULL);
-
+ err_ret:
+ GNUNET_break (0);
}
+
int main(int argc, char *const argv[])
{
struct GNUNET_SIGNAL_Context *shc_chld;
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+ int ret;
+
+ if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
+ return 2;
+ if (NULL == (sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO,
+ GNUNET_NO, GNUNET_NO)))
+ {
+ GNUNET_break (0);
+ return 1;
+ }
+ shc_chld =
+ GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, &sighandler_child_death);
+ ret =
+ GNUNET_PROGRAM_run (argc, argv, "test-pty",
+ gettext_noop
+ ("msh-waiter test program"),
+ options, &run, NULL);
+ GNUNET_SIGNAL_handler_uninstall (shc_chld);
+ GNUNET_DISK_pipe_close (sigpipe);
+ GNUNET_free ((void *) argv);
+ return ret;
+}
+
+#if 0
const char *ptysname;
int cnt;
int ptym;
@@ -253,4 +737,5 @@
GNUNET_DISK_file_close (chld_io);
GNUNET_SIGNAL_handler_uninstall (shc_chld);
return 0;
-}
+
+#endif
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [GNUnet-SVN] r29924 - msh/src,
gnunet <=