1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
|
#define _BSD_SOURCE
#include <sys/ioctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define TTYDEFCHARS
#include <termios.h>
#include <sys/ttydefaults.h>
#undef TTYDEFCHARS
#if defined(__APPLE__)
#include <util.h>
#elif defined(__GLIBC__)
#include <pty.h>
#else /* bsd without glibc */
#include <libutil.h>
#endif
#include <HsFFI.h>
#include "fork_exec_with_pty.h"
/* Should be exported by unistd.h, but isn't on OSX. */
extern char **environ;
/* Fork and exec with a pty, returning the fd of the master pty. */
int
fork_exec_with_pty
( HsInt sx
, HsInt sy
, int search
, const char *file
, char *const argv[]
, char *const env[]
, HsInt *child_pid
)
{
int pty;
int packet_mode = 1;
struct winsize ws;
/* Set the terminal size and settings. */
memset(&ws, 0, sizeof ws);
ws.ws_col = sx;
ws.ws_row = sy;
/* Fork and exec, returning the master pty. */
*child_pid = forkpty(&pty, NULL, NULL, &ws);
switch (*child_pid) {
case -1:
return -1;
case 0:
/* If an environment is specified, override the old one. */
if (env) environ = (char**) env;
/* Search user's path or not. */
if (search) execvp(file, argv);
else execv(file, argv);
perror("exec failed");
exit(EXIT_FAILURE);
default:
/* Switch the pty to packet mode, we'll deal with packeting on the
haskell side of things. */
if (ioctl(pty, TIOCPKT, &packet_mode) == -1) return 1;
return pty;
}
}
|