1 /* source: xio-pty.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for creating pty addresses */
7 #include "xiosysincludes.h"
10 #include "xio-named.h"
11 #include "xio-termios.h"
16 /* here define the preferred polling intervall, in seconds */
17 #define PTY_INTERVALL 1,0 /* for struct timespec */
19 #define MAXPTYNAMELEN 64
21 static int xioopen_pty(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*fd
, const struct addrdesc
*addrdesc
);
23 const struct addrdesc xioaddr_pty
= { "PTY", 3, xioopen_pty
, GROUP_NAMED
|GROUP_FD
|GROUP_TERMIOS
|GROUP_PTY
, 0, 0, 0 HELP("") };
25 const struct optdesc opt_symbolic_link
= { "symbolic-link", "link", OPT_SYMBOLIC_LINK
, GROUP_PTY
, PH_LATE
, TYPE_FILENAME
, OFUNC_SPEC
, 0, 0 };
27 const struct optdesc opt_pty_wait_slave
= { "pty-wait-slave", "wait-slave", OPT_PTY_WAIT_SLAVE
, GROUP_PTY
, PH_EARLY
, TYPE_BOOL
, OFUNC_SPEC
, 0, 0 };
28 const struct optdesc opt_pty_intervall
= { "pty-interval", NULL
, OPT_PTY_INTERVALL
, GROUP_PTY
, PH_EARLY
, TYPE_TIMESPEC
, OFUNC_SPEC
, 0, 0 };
29 #endif /* HAVE_POLL */
31 static int xioopen_pty(
37 const struct addrdesc
*addrdesc
)
39 /* we expect the form: filename */
40 struct single
*sfd
= &xfd
->stream
;
41 int ptyfd
= -1; /* master */
42 int ttyfd
= -1; /* slave */
43 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
44 bool useptmx
= false; /* use /dev/ptmx or equivalent */
47 bool useopenpty
= false; /* try only openpty */
48 #endif /* HAVE_OPENPTY */
49 char ptyname
[MAXPTYNAMELEN
];
51 char *linkname
= NULL
;
52 bool opt_unlink_close
= true; /* remove symlink afterwards */
53 bool wait_slave
= false; /* true would be better for many platforms, but
54 some OSes cannot handle this, and for common
55 default behaviour as well as backward
56 compatibility we choose "no" as default */
57 struct timespec pollintv
= { PTY_INTERVALL
};
60 xio_syntax(argv
[0], 0, argc
-1, addrdesc
->syntax
);
64 if (sfd
->howtoend
== END_UNSPEC
)
65 sfd
->howtoend
= END_CLOSE
;
67 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return -1;
68 applyopts(sfd
, -1, opts
, PH_INIT
);
70 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
72 /* trying to set user-early, perm-early etc. here might be useless because
73 file system entry is eventually available only past pty creation */
74 /* name not yet known; umask should not be handled with this function! */
75 /* umask does not affect resulting mode, on Linux 2.4 */
76 applyopts_named("", opts
, PH_EARLY
); /* umask! */
78 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
79 retropt_bool(opts
, OPT_PTMX
, &useptmx
);
82 retropt_bool(opts
, OPT_OPENPTY
, &useopenpty
);
85 #if (defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC))
87 useopenpty
= !useptmx
;
88 # else /* !HAVE_OPENPTY */
90 # endif /* !HAVE_OPENPTY */
94 # endif /* HAVE_OPENPTY */
95 #endif /* ! (defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)) */
98 retropt_bool(opts
, OPT_PTY_WAIT_SLAVE
, &wait_slave
);
99 retropt_timespec(opts
, OPT_PTY_INTERVALL
, &pollintv
);
100 #endif /* HAVE_POLL */
102 if (applyopts_single(sfd
, opts
, PH_INIT
) < 0) return -1;
103 applyopts2(sfd
, -1, opts
, PH_INIT
, PH_EARLY
);
105 applyopts(sfd
, -1, opts
, PH_PREBIGEN
);
110 if ((result
= Openpty(&ptyfd
, &ttyfd
, ptyname
, NULL
, NULL
)) < 0) {
111 Error4("openpty(%p, %p, %p, NULL, NULL): %s",
112 &ptyfd
, &ttyfd
, ptyname
, strerror(errno
));
115 Notice1("PTY is %s", ptyname
);
117 #endif /* HAVE_OPENPTY */
119 #if defined(HAVE_DEV_PTMX)
120 # define PTMX "/dev/ptmx" /* Linux */
122 # define PTMX "/dev/ptc" /* AIX 4.3.3 */
124 #if HAVE_DEV_PTMX || HAVE_DEV_PTC
125 if (useptmx
|| ptyfd
< 0) {
126 if ((ptyfd
= Open(PTMX
, O_RDWR
|O_NOCTTY
, 0620)) < 0) {
127 Warn1("open(\""PTMX
"\", O_RDWR|O_NOCTTY, 0620): %s",
131 ;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/
134 /* we used PTMX before forking */
135 /*0 extern char *ptsname(int);*/
136 #if HAVE_GRANTPT /* AIX, not Linux */
137 if (Grantpt(ptyfd
)/*!*/ < 0) {
138 Warn2("grantpt(%d): %s", ptyfd
, strerror(errno
));
140 #endif /* HAVE_GRANTPT */
142 if (Unlockpt(ptyfd
)/*!*/ < 0) {
143 Warn2("unlockpt(%d): %s", ptyfd
, strerror(errno
));
145 #endif /* HAVE_UNLOCKPT */
146 #if HAVE_PROTOTYPE_LIB_ptsname /* AIX, not Linux */
147 if ((tn
= Ptsname(ptyfd
)) == NULL
) {
148 Warn2("ptsname(%d): %s", ptyfd
, strerror(errno
));
150 Notice1("PTY is %s", tn
);
152 #endif /* HAVE_PROTOTYPE_LIB_ptsname */
154 if ((tn
= Ttyname(ptyfd
)) == NULL
) {
155 Warn2("ttyname(%d): %s", ptyfd
, strerror(errno
));
158 ptyname
[0] = '\0'; strncat(ptyname
, tn
, MAXPTYNAMELEN
-1);
161 #endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
163 if (!retropt_string(opts
, OPT_SYMBOLIC_LINK
, &linkname
)) {
164 xio_unlink(linkname
, E_ERROR
);
165 if (Symlink(ptyname
, linkname
) < 0) {
166 Error3("symlink(\"%s\", \"%s\"): %s",
167 ptyname
, linkname
, strerror(errno
));
169 if (opt_unlink_close
) {
170 if ((sfd
->unlink_close
= strdup(linkname
)) == NULL
) {
171 Error1("strdup(\"%s\"): out of memory", linkname
);
173 sfd
->opt_unlink_close
= true;
177 applyopts_named(ptyname
, opts
, PH_PASTOPEN
);
178 applyopts_named(ptyname
, opts
, PH_FD
);
180 applyopts_cloexec(ptyfd
, opts
);/*!*/
181 sfd
->dtype
= XIODATA_PTY
;
183 applyopts(sfd
, ttyfd
, opts
, PH_FD
);
186 /* special handling of user-late etc.; with standard behaviour (up to
187 1.7.1.1) they affected /dev/ptmx instead of /dev/pts/N */
188 uid_t uid
= -1, gid
= -1;
192 dont
= retropt_uid(opts
, OPT_USER_LATE
, &uid
);
193 dont
&= retropt_gid(opts
, OPT_GROUP_LATE
, &gid
);
196 if (Chown(ptyname
, uid
, gid
) < 0) {
197 Error4("chown(\"%s\", %d, %d): %s",
198 ptyname
, uid
, gid
, strerror(errno
));
202 if (retropt_mode(opts
, OPT_PERM_LATE
, &perm
) == 0) {
203 if (Chmod(ptyname
, perm
) < 0) {
204 Error3("chmod(\"%s\", %03o): %s",
205 ptyname
, perm
, strerror(errno
));
212 applyopts(sfd
, -1, opts
, PH_LATE
);
213 if (applyopts_single(sfd
, opts
, PH_LATE
) < 0)
217 /* if you can and wish: */
219 /* try to wait until someone opens the slave side of the pty */
220 /* we want to get a HUP (hangup) condition on the pty */
221 #if HAVE_DEV_PTMX || HAVE_DEV_PTC
223 ttyfd
= Open(tn
, O_RDWR
|O_NOCTTY
, 0620);
231 #endif /* HAVE_OPENPTY */
233 /* now we poll until the HUP vanishes - this indicates a slave conn. */
237 ufd
.events
= (POLLHUP
);
238 if (Poll(&ufd
, 1, 0) < 0) {
239 Error3("poll({%d, 0x%04hu,}, 1, 0): %s",
240 ufd
.fd
, ufd
.events
, strerror(errno
));
241 /*! close something */
244 if (!(ufd
.revents
& POLLHUP
)) {
247 Nanosleep(&pollintv
, NULL
);
251 #endif /* HAVE_POLL */
255 #endif /* WITH_PTY */