]> git.proxmox.com Git - mirror_lxc.git/blame - src/include/openpty.c
src: Don't use ifdef/defined for config.h
[mirror_lxc.git] / src / include / openpty.c
CommitLineData
35eb5cdc
CB
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#define _GNU_SOURCE
e827ff7e
SG
4#include <errno.h>
5#include <fcntl.h>
6#include <limits.h>
7#include <stdlib.h>
8#include <string.h>
35eb5cdc
CB
9#include <sys/ioctl.h>
10#include <sys/types.h>
e827ff7e
SG
11#include <termios.h>
12#include <unistd.h>
e827ff7e 13
6ae86a9c 14#if HAVE_PTY_H
35eb5cdc
CB
15#include <pty.h>
16#endif
e827ff7e 17
35eb5cdc 18static int pts_name(int fd, char **pts, size_t buf_len)
e827ff7e 19{
35eb5cdc
CB
20 int rv;
21 char *buf = *pts;
22
23 for (;;) {
24 char *new_buf;
25
26 if (buf_len) {
27 rv = ptsname_r(fd, buf, buf_len);
28
29 if (rv != 0 || memchr(buf, '\0', buf_len))
30 /* We either got an error, or we succeeded and the
31 returned name fit in the buffer. */
32 break;
33
34 /* Try again with a longer buffer. */
35 buf_len += buf_len; /* Double it */
36 } else
37 /* No initial buffer; start out by mallocing one. */
38 buf_len = 128; /* First time guess. */
39
40 if (buf != *pts)
41 /* We've already malloced another buffer at least once. */
42 new_buf = realloc(buf, buf_len);
43 else
44 new_buf = malloc(buf_len);
45 if (!new_buf) {
46 rv = -1;
47 break;
48 }
49 buf = new_buf;
50 }
51
52 if (rv == 0)
53 *pts = buf; /* Return buffer to the user. */
54 else if (buf != *pts)
55 free(buf); /* Free what we malloced when returning an error. */
56
57 return rv;
58}
59
60int __unlockpt(int fd)
61{
62#ifdef TIOCSPTLCK
63 int unlock = 0;
64
65 if (ioctl(fd, TIOCSPTLCK, &unlock)) {
66 if (errno != EINVAL)
67 return -1;
68 }
69#endif
70 return 0;
71}
72
73int openpty(int *ptx, int *pty, char *name, const struct termios *termp,
74 const struct winsize *winp)
75{
76 char _buf[PATH_MAX];
77 char *buf = _buf;
78 int ptx_fd, ret = -1, pty_fd = -1;
79
80 *buf = '\0';
81
82 ptx_fd = open("/dev/ptmx", O_RDWR | O_NOCTTY);
83 if (ptx_fd == -1)
84 return -1;
85
86 if (__unlockpt(ptx_fd))
87 goto on_error;
88
89#ifdef TIOCGPTPEER
90 /* Try to allocate pty_fd solely based on ptx_fd first. */
91 pty_fd = ioctl(ptx_fd, TIOCGPTPEER, O_RDWR | O_NOCTTY);
92#endif
93 if (pty_fd == -1) {
94 /* Fallback to path-based pty_fd allocation in case kernel doesn't
95 * support TIOCGPTPEER.
96 */
97 if (pts_name(ptx_fd, &buf, sizeof(_buf)))
98 goto on_error;
e827ff7e 99
35eb5cdc
CB
100 pty_fd = open(buf, O_RDWR | O_NOCTTY);
101 if (pty_fd == -1)
102 goto on_error;
103 }
e827ff7e 104
35eb5cdc
CB
105 if (termp)
106 tcsetattr(pty_fd, TCSAFLUSH, termp);
107#ifdef TIOCSWINSZ
108 if (winp)
109 ioctl(pty_fd, TIOCSWINSZ, winp);
110#endif
e827ff7e 111
35eb5cdc
CB
112 *ptx = ptx_fd;
113 *pty = pty_fd;
114 if (name != NULL) {
115 if (*buf == '\0')
116 if (pts_name(ptx_fd, &buf, sizeof(_buf)))
117 goto on_error;
e827ff7e 118
35eb5cdc
CB
119 strcpy(name, buf);
120 }
e827ff7e 121
35eb5cdc 122 ret = 0;
e827ff7e 123
35eb5cdc
CB
124on_error:
125 if (ret == -1) {
126 close(ptx_fd);
e827ff7e 127
35eb5cdc
CB
128 if (pty_fd != -1)
129 close(pty_fd);
130 }
e827ff7e 131
35eb5cdc
CB
132 if (buf != _buf)
133 free(buf);
e827ff7e 134
35eb5cdc 135 return ret;
e827ff7e 136}