-
-
Save bomsi/027fc0e454a2ec5e2822ce2a5bfbcda6 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define _XOPEN_SOURCE 600 | |
#define _BSD_SOURCE | |
#include <unistd.h> | |
#include <termios.h> | |
#include <sys/types.h> | |
#include <sys/ioctl.h> | |
#include <sys/select.h> | |
#include <stdlib.h> | |
#include <stdio.h> | |
#include <fcntl.h> | |
#include <errno.h> | |
#include <assert.h> | |
#include <string.h> | |
int main(int argc, char** argv) { | |
int pmd, rc, sfd; | |
char *name; | |
pid_t child; | |
/* open an unused pseudoterminal master device */ | |
pmd = posix_openpt(O_RDWR); | |
assert(pmd != -1); | |
/* grant access to the slave pseudoterminal */ | |
rc = grantpt(pmd); | |
assert(rc != -1); | |
/* unlock the slave pseudoterminal device corresponding | |
to the master pseudoterminal referred */ | |
rc = unlockpt(pmd); | |
assert(rc != -1); | |
/* get the slave pseudoterminal device name */ | |
name = ptsname(pmd); | |
assert(name != NULL); | |
printf("Slave side name %s\n", name); | |
/* open the slave side */ | |
sfd = open(name, O_RDWR); | |
assert(sfd != -1); | |
child = fork(); | |
assert(child != -1); | |
if (child == 0) { | |
/* child process */ | |
struct termios os, ns; | |
/* close the master side */ | |
close(pmd); | |
/* save old settings */ | |
rc = tcgetattr(sfd, &os); | |
/* set raw mode (input available character by character, | |
echoing disabled, all special processing disabled */ | |
ns = os; | |
cfmakeraw(&ns); | |
/* apply the change now */ | |
tcsetattr(sfd, TCSANOW, &ns); | |
/* sanity check */ | |
rc = isatty(sfd); | |
assert(rc == 1); | |
/* close stdin, stdout and stderr of the current terminal | |
they will come from the slave side */ | |
close(0); | |
close(1); | |
close(2); | |
/* pseudoterminal becomes stdin, stdout, stderr */ | |
dup(sfd); | |
dup(sfd); | |
dup(sfd); | |
/* original file descriptor can be closed */ | |
close(sfd); | |
/* make this process the new session leader */ | |
setsid(); | |
/* set the slave side to be the controlling terminal */ | |
rc = ioctl(0, TIOCSCTTY, 1); | |
assert(rc != -1); | |
{ /* execute the child */ | |
char** cargv; | |
int i; | |
cargv = (char**)malloc(argc * sizeof(char*)); | |
assert(cargv != NULL); | |
for (i = 1; i < argc; ++i) { | |
cargv[i - 1] = strdup(argv[i]); | |
} | |
cargv[i - 1] = NULL; | |
rc = execvp(cargv[0], cargv); | |
} | |
} | |
else { | |
/* master process */ | |
fd_set fi; | |
char buf[128]; | |
/* close the slave side */ | |
close(sfd); | |
while (1) { | |
/* wait on stdin and the master side */ | |
FD_ZERO(&fi); | |
FD_SET(0, &fi); | |
FD_SET(pmd, &fi); | |
rc = select(pmd + 1, &fi, NULL, NULL, NULL); | |
assert(rc != -1); | |
if(FD_ISSET(0, &fi)) { | |
/* data on stdin */ | |
rc = read(0, buf, sizeof(buf)); | |
if (rc > 0) { | |
/* write it on the master side */ | |
write(pmd, buf, rc); | |
} | |
else { | |
if (rc < 0) { | |
fprintf(stderr, "Error reading on stdin\n"); | |
assert(0); | |
} | |
} | |
} | |
if(FD_ISSET(pmd, &fi)) { | |
/* data on the master side */ | |
rc = read(pmd, buf, sizeof(buf)); | |
if (rc > 0) { | |
/* write to stdout */ | |
write(1, buf, rc); | |
} | |
else { | |
if (rc < 0) { | |
if (errno == EIO) { | |
/* child died */ | |
break; | |
} | |
fprintf(stderr, "Error reading on master\n"); | |
} | |
} | |
} | |
} | |
} | |
fprintf(stderr, "Done.\n"); | |
return rc; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment