add custom pty interface
This commit is contained in:
parent
bd87f194f2
commit
c68fc6de5e
3 changed files with 170 additions and 0 deletions
24
cli/main.c
Normal file
24
cli/main.c
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
#include "mkpty.h"
|
||||||
|
#include "sys/types.h"
|
||||||
|
|
||||||
|
|
||||||
|
// struct d_window {
|
||||||
|
// int ptmx; // fd
|
||||||
|
// };
|
||||||
|
|
||||||
|
// struct d_window new_window() {
|
||||||
|
// struct d_window w = {
|
||||||
|
// .ptmx = posix_openpt(O_RDWR | O_NOCTTY),
|
||||||
|
// };
|
||||||
|
// }
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
pid_t pid;
|
||||||
|
switch (pid = forkmkpty()) {
|
||||||
|
case -1:
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
132
cli/mkpty.c
Normal file
132
cli/mkpty.c
Normal file
|
|
@ -0,0 +1,132 @@
|
||||||
|
/* _XOPEN_SOURCE unlocks <stdlib.h> pty/ptmx/pts declarations. */
|
||||||
|
#define _XOPEN_SOURCE 600
|
||||||
|
/* _GNU_SOURCE unlocks the ptsname_r declaration*/
|
||||||
|
#define _GNU_SOURCE
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <asm/termbits.h> /* TIOC* constants */
|
||||||
|
#include <sys/ioctl.h>
|
||||||
|
|
||||||
|
#ifdef PATH_MAX
|
||||||
|
# define SNAME_MAX PATH_MAX
|
||||||
|
#else
|
||||||
|
# define SNAME_MAX 512
|
||||||
|
#endif /* PATH_MAX */
|
||||||
|
|
||||||
|
/* Allocate PTY master and slave file descriptors.
|
||||||
|
* errno will have been set if newpty() fails.
|
||||||
|
*
|
||||||
|
* NOTE: This function is my alternative to GLibC's
|
||||||
|
* openpty() function. It exists as a learning resource.
|
||||||
|
* REF: glibc.git:/login/openpty.c
|
||||||
|
*/
|
||||||
|
int mkpty(int *fdmx, int *fds) {
|
||||||
|
int _fdmx = -1, _fds = -1;
|
||||||
|
char sname[SNAME_MAX];
|
||||||
|
|
||||||
|
// Configure PTY master (file descriptor)
|
||||||
|
_fdmx = posix_openpt(O_RDWR | O_NOCTTY);
|
||||||
|
if (_fdmx == -1)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (grantpt(_fdmx))
|
||||||
|
goto fail;
|
||||||
|
if (unlockpt(_fdmx))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
#ifdef TIOCGPTPEER
|
||||||
|
/* Try to allocate slave fd solely based on PTMX fd first. */
|
||||||
|
_fds = ioctl(_fdmx, TIOCGPTPEER, O_RDWR | O_NOCTTY);
|
||||||
|
#endif
|
||||||
|
if (_fds == -1) {
|
||||||
|
/* Fallback to path-based slave fd allocation
|
||||||
|
* (if the kernel doesn't support TIOCGPTPEER, ie Linux <4.13) */
|
||||||
|
if(ptsname_r(_fdmx, sname, sizeof(sname)))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
_fds = open(sname, O_RDWR | O_NOCTTY);
|
||||||
|
if (_fds == -1)
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate file descriptors via parameters
|
||||||
|
*fdmx = _fdmx;
|
||||||
|
*fds = _fds;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
|
||||||
|
fail:
|
||||||
|
if (_fdmx == -1) {
|
||||||
|
close(_fdmx);
|
||||||
|
if (_fds == -1)
|
||||||
|
close(_fds);
|
||||||
|
}
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
pid_t forkmkpty() {
|
||||||
|
int fdmx, fds;
|
||||||
|
pid_t pid;
|
||||||
|
if (mkpty(&fdmx, &fds))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
switch (pid = fork()) {
|
||||||
|
case -1:
|
||||||
|
close(fdmx);
|
||||||
|
close(fds);
|
||||||
|
return -1;
|
||||||
|
case 0:
|
||||||
|
/* Child Process */
|
||||||
|
close(fdmx);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Parent Process */
|
||||||
|
close(fds);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Both Processes */
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set pseudoterminal slave's window size.
|
||||||
|
* Returns 0 on success, and fails with -1 if the kernel doesn't
|
||||||
|
* implement this, or 1 for general errors (errno will be set).
|
||||||
|
* NOTE: Typically this is part of a glibc openpty() call.
|
||||||
|
*/
|
||||||
|
int setptsxy(const unsigned short rows, const unsigned short cols, const int fds) {
|
||||||
|
#ifndef TIOCSWINSZ
|
||||||
|
/* Fail if kernel doesn't support TIOCSWINSZ. */
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
struct winsize win = {
|
||||||
|
.ws_row = rows,
|
||||||
|
.ws_col = cols,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (ioctl(fds, TIOCSWINSZ, &win))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
#endif /* TIOCSWINSZ */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get pseudoterminal slave's window size.
|
||||||
|
* Returns 0 on success, and fails with -1 if the kernel doesn't
|
||||||
|
* implement this, or 1 for general errors (errno will be set).
|
||||||
|
*/
|
||||||
|
int getptsxy(unsigned short *rows, unsigned short *cols, const int fds) {
|
||||||
|
#ifndef TIOCGWINSZ
|
||||||
|
/* Fail if kernel doesn't support TIOCGWINSZ. */
|
||||||
|
return -1;
|
||||||
|
#else
|
||||||
|
struct winsize win = (struct winsize){ 0 };
|
||||||
|
if (ioctl(fds, TIOCGWINSZ, &win))
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
*rows = win.ws_row;
|
||||||
|
*cols = win.ws_col;
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
#endif /* TIOCGWINSZ */
|
||||||
|
}
|
||||||
14
cli/mkpty.h
Normal file
14
cli/mkpty.h
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
#ifndef DORNE_MKPTY_H
|
||||||
|
#define DORNE_MKPTY_H
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
/* Custom implementations of openpty() */
|
||||||
|
int mkpty(int *fdmx, int *fds);
|
||||||
|
/* Custom implementations of forkpty() */
|
||||||
|
pid_t forkmkpty();
|
||||||
|
|
||||||
|
int setptsxy(const unsigned short rows, const unsigned short cols, const int fds);
|
||||||
|
int getptsxy(unsigned short *rows, unsigned short *cols, const int fds);
|
||||||
|
|
||||||
|
#endif /* DORNE_MKPTY_H */
|
||||||
Loading…
Add table
Add a link
Reference in a new issue