Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
openpty: improve implementation and handling of platforms without it
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
- Loading branch information
Christian Brauner
committed
Jul 6, 2020
1 parent
6d3b685
commit 35eb5cd
Showing
6 changed files
with
136 additions
and
88 deletions.
There are no files selected for viewing
This file contains 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
This file contains 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,136 @@ | ||
/* | ||
* openpty: glibc implementation | ||
* | ||
* Copyright (C) 1998, 1999, 2004 Free Software Foundation, Inc. | ||
* | ||
* Authors: | ||
* Zack Weinberg <zack@rabi.phys.columbia.edu>, 1998. | ||
* | ||
* This library is free software; you can redistribute it and/or | ||
* modify it under the terms of the GNU Lesser General Public | ||
* License as published by the Free Software Foundation; either | ||
* version 2.1 of the License, or (at your option) any later version. | ||
* This library is distributed in the hope that it will be useful, | ||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
* Lesser General Public License for more details. | ||
* You should have received a copy of the GNU Lesser General Public | ||
* License along with this library; if not, write to the Free Software | ||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
*/ | ||
|
||
#define _XOPEN_SOURCE /* See feature_test_macros(7) */ | ||
/* SPDX-License-Identifier: LGPL-2.1+ */ | ||
|
||
#define _GNU_SOURCE | ||
#include <errno.h> | ||
#include <fcntl.h> | ||
#include <limits.h> | ||
#include <stdlib.h> | ||
#include <string.h> | ||
#include <sys/ioctl.h> | ||
#include <sys/types.h> | ||
#include <termios.h> | ||
#include <unistd.h> | ||
#include <sys/types.h> | ||
#include <sys/ioctl.h> | ||
|
||
#define _PATH_DEVPTMX "/dev/ptmx" | ||
#ifdef HAVE_PTY_H | ||
#include <pty.h> | ||
#endif | ||
|
||
int openpty (int *aptx, int *apty, char *name, struct termios *termp, | ||
struct winsize *winp) | ||
static int pts_name(int fd, char **pts, size_t buf_len) | ||
{ | ||
char buf[PATH_MAX]; | ||
int ptx, pty; | ||
int rv; | ||
char *buf = *pts; | ||
|
||
for (;;) { | ||
char *new_buf; | ||
|
||
if (buf_len) { | ||
rv = ptsname_r(fd, buf, buf_len); | ||
|
||
if (rv != 0 || memchr(buf, '\0', buf_len)) | ||
/* We either got an error, or we succeeded and the | ||
returned name fit in the buffer. */ | ||
break; | ||
|
||
/* Try again with a longer buffer. */ | ||
buf_len += buf_len; /* Double it */ | ||
} else | ||
/* No initial buffer; start out by mallocing one. */ | ||
buf_len = 128; /* First time guess. */ | ||
|
||
if (buf != *pts) | ||
/* We've already malloced another buffer at least once. */ | ||
new_buf = realloc(buf, buf_len); | ||
else | ||
new_buf = malloc(buf_len); | ||
if (!new_buf) { | ||
rv = -1; | ||
break; | ||
} | ||
buf = new_buf; | ||
} | ||
|
||
if (rv == 0) | ||
*pts = buf; /* Return buffer to the user. */ | ||
else if (buf != *pts) | ||
free(buf); /* Free what we malloced when returning an error. */ | ||
|
||
return rv; | ||
} | ||
|
||
int __unlockpt(int fd) | ||
{ | ||
#ifdef TIOCSPTLCK | ||
int unlock = 0; | ||
|
||
if (ioctl(fd, TIOCSPTLCK, &unlock)) { | ||
if (errno != EINVAL) | ||
return -1; | ||
} | ||
#endif | ||
return 0; | ||
} | ||
|
||
int openpty(int *ptx, int *pty, char *name, const struct termios *termp, | ||
const struct winsize *winp) | ||
{ | ||
char _buf[PATH_MAX]; | ||
char *buf = _buf; | ||
int ptx_fd, ret = -1, pty_fd = -1; | ||
|
||
*buf = '\0'; | ||
|
||
ptx_fd = open("/dev/ptmx", O_RDWR | O_NOCTTY); | ||
if (ptx_fd == -1) | ||
return -1; | ||
|
||
if (__unlockpt(ptx_fd)) | ||
goto on_error; | ||
|
||
#ifdef TIOCGPTPEER | ||
/* Try to allocate pty_fd solely based on ptx_fd first. */ | ||
pty_fd = ioctl(ptx_fd, TIOCGPTPEER, O_RDWR | O_NOCTTY); | ||
#endif | ||
if (pty_fd == -1) { | ||
/* Fallback to path-based pty_fd allocation in case kernel doesn't | ||
* support TIOCGPTPEER. | ||
*/ | ||
if (pts_name(ptx_fd, &buf, sizeof(_buf))) | ||
goto on_error; | ||
|
||
ptx = open(_PATH_DEVPTMX, O_RDWR); | ||
if (ptx == -1) | ||
return -1; | ||
pty_fd = open(buf, O_RDWR | O_NOCTTY); | ||
if (pty_fd == -1) | ||
goto on_error; | ||
} | ||
|
||
if (grantpt(ptx)) | ||
goto fail; | ||
if (termp) | ||
tcsetattr(pty_fd, TCSAFLUSH, termp); | ||
#ifdef TIOCSWINSZ | ||
if (winp) | ||
ioctl(pty_fd, TIOCSWINSZ, winp); | ||
#endif | ||
|
||
if (unlockpt(ptx)) | ||
goto fail; | ||
*ptx = ptx_fd; | ||
*pty = pty_fd; | ||
if (name != NULL) { | ||
if (*buf == '\0') | ||
if (pts_name(ptx_fd, &buf, sizeof(_buf))) | ||
goto on_error; | ||
|
||
if (ptyname_r(ptx, buf, sizeof buf)) | ||
goto fail; | ||
strcpy(name, buf); | ||
} | ||
|
||
pty = open(buf, O_RDWR | O_NOCTTY); | ||
if (pty == -1) | ||
goto fail; | ||
ret = 0; | ||
|
||
/* XXX Should we ignore errors here? */ | ||
if (termp) | ||
tcsetattr(pty, TCSAFLUSH, termp); | ||
if (winp) | ||
ioctl(pty, TIOCSWINSZ, winp); | ||
on_error: | ||
if (ret == -1) { | ||
close(ptx_fd); | ||
|
||
*aptx = ptx; | ||
*apty = pty; | ||
if (name != NULL) | ||
strcpy(name, buf); | ||
if (pty_fd != -1) | ||
close(pty_fd); | ||
} | ||
|
||
return 0; | ||
if (buf != _buf) | ||
free(buf); | ||
|
||
fail: | ||
close(ptx); | ||
return -1; | ||
return ret; | ||
} |
This file contains 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
This file contains 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
This file contains 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
This file contains 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