/* allocpty.c v0.1 by Pegasus Epsilon <pegasus@pimpninjas.org>
* Distribute Unmodified - http://pegasus.pimpninjas.org/license
*
* compile with -lutil -pthread
*
* Changelog:
* v0.0 First version, does what I intended it to, nothing else.
* v0.1 Now attempts to put terminal in raw mode to avoid quirks of allocpty
* inside a pty.
* Added #define to stop fileno not existing with -Wall -pedantic, etc.
* Added environment support.
*/
#define _GNU_SOURCE
#define _POSIX_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <pty.h>
#include <pthread.h>
void usage (char *name) {
printf("%s v0.1 by \"Pegasus Epsilon\" <pegasus@pimpninjas.org>", name);
puts("Runs any program in a new pty, at any time.");
printf("Usage: %s <program> <args>", name);
if (strcmp(name, "allocpty"))
puts("Note: The original name of this program is 'allocpty'");
exit(0);
}
void die (char *msg) {
perror(msg);
exit(1);
}
void *read_from_child (void *ign) {
char buffer;
while (read(fileno(stdin), &buffer, 1) > 0)
if (write(3, &buffer, 1) < 1) die("failed to write to child");
exit(0);
}
int main (int argc, char **argv, char **envp) {
int pty;
char buffer;
pthread_t thread;
if (argc < 2) usage(*argv);
if (0 == forkpty(&pty, NULL, NULL, NULL)) {
execvpe(argv[1], &argv[1], envp);
/* we only get here if we can't execvp() */
die("can't execvpe()");
} else {
struct termios flags;
if (!tcgetattr(0, &flags)) {
/* this may fail, that's okay */
flags.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON | ECHO);
flags.c_lflag &= ~(ECHO | ICANON | IEXTEN | ISIG);
tcsetattr(0, TCSANOW, &flags);
}
pthread_create(&thread, NULL, read_from_child, NULL);
while (read(3, &buffer, 1) > 0)
if (write(fileno(stdout), &buffer, 1) < 1) die("stdout write failed");
}
return 0;
}