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
, unsigned groups
, int dummy1
, int dummy2
, int dummy3
);
23 const struct addrdesc addr_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(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xfd
, unsigned groups
, int dummy1
, int dummy2
, int dummy3
) {
32 /* we expect the form: filename */
33 int ptyfd
= -1, ttyfd
= -1;
34 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
35 bool useptmx
= false; /* use /dev/ptmx or equivalent */
38 bool useopenpty
= false; /* try only openpty */
39 #endif /* HAVE_OPENPTY */
40 char ptyname
[MAXPTYNAMELEN
];
42 char *linkname
= NULL
;
43 bool opt_unlink_close
= true; /* remove symlink afterwards */
44 bool wait_slave
= false; /* true would be better for many platforms, but
45 some OSes cannot handle this, and for common
46 default behaviour as well as backward
47 compatibility we choose "no" as default */
48 struct timespec pollintv
= { PTY_INTERVALL
};
51 Error2("%s: wrong number of parameters (%d instead of 0)", argv
[0], argc
-1);
54 xfd
->stream
.howtoend
= END_CLOSE
;
56 if (applyopts_single(&xfd
->stream
, opts
, PH_INIT
) < 0) return -1;
57 applyopts(-1, opts
, PH_INIT
);
59 retropt_bool(opts
, OPT_UNLINK_CLOSE
, &opt_unlink_close
);
61 /* trying to set user-early, perm-early etc. here might be useless because
62 file system entry is eventually available only past pty creation */
63 /* name not yet known; umask should not be handled with this function! */
64 /* umask does not affect resulting mode, on Linux 2.4 */
65 applyopts_named("", opts
, PH_EARLY
); /* umask! */
67 #if defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)
68 retropt_bool(opts
, OPT_PTMX
, &useptmx
);
71 retropt_bool(opts
, OPT_OPENPTY
, &useopenpty
);
74 #if (defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC))
76 useopenpty
= !useptmx
;
77 # else /* !HAVE_OPENPTY */
79 # endif /* !HAVE_OPENPTY */
83 # endif /* HAVE_OPENPTY */
84 #endif /* ! (defined(HAVE_DEV_PTMX) || defined(HAVE_DEV_PTC)) */
87 retropt_bool(opts
, OPT_PTY_WAIT_SLAVE
, &wait_slave
);
88 retropt_timespec(opts
, OPT_PTY_INTERVALL
, &pollintv
);
89 #endif /* HAVE_POLL */
91 if (applyopts_single(&xfd
->stream
, opts
, PH_INIT
) < 0) return -1;
92 applyopts2(-1, opts
, PH_INIT
, PH_EARLY
);
94 applyopts(-1, opts
, PH_PREBIGEN
);
96 #if defined(HAVE_DEV_PTMX)
97 # define PTMX "/dev/ptmx" /* Linux */
99 # define PTMX "/dev/ptc" /* AIX 4.3.3 */
101 #if HAVE_DEV_PTMX || HAVE_DEV_PTC
103 if ((ptyfd
= Open(PTMX
, O_RDWR
|O_NOCTTY
, 0620)) < 0) {
104 Warn1("open(\""PTMX
"\", O_RDWR|O_NOCTTY, 0620): %s",
108 ;/*0 Info1("open(\""PTMX"\", O_RDWR|O_NOCTTY, 0620) -> %d", ptyfd);*/
110 if (ptyfd
>= 0 && ttyfd
< 0) {
111 /* we used PTMX before forking */
112 /*0 extern char *ptsname(int);*/
113 #if HAVE_GRANTPT /* AIX, not Linux */
114 if (Grantpt(ptyfd
)/*!*/ < 0) {
115 Warn2("grantpt(%d): %s", ptyfd
, strerror(errno
));
117 #endif /* HAVE_GRANTPT */
119 if (Unlockpt(ptyfd
)/*!*/ < 0) {
120 Warn2("unlockpt(%d): %s", ptyfd
, strerror(errno
));
122 #endif /* HAVE_UNLOCKPT */
123 #if HAVE_PROTOTYPE_LIB_ptsname /* AIX, not Linux */
124 if ((tn
= Ptsname(ptyfd
)) == NULL
) {
125 Warn2("ptsname(%d): %s", ptyfd
, strerror(errno
));
127 Notice1("PTY is %s", tn
);
129 #endif /* HAVE_PROTOTYPE_LIB_ptsname */
131 if ((tn
= Ttyname(ptyfd
)) == NULL
) {
132 Warn2("ttyname(%d): %s", ptyfd
, strerror(errno
));
135 ptyname
[0] = '\0'; strncat(ptyname
, tn
, MAXPTYNAMELEN
-1);
138 #endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
142 if ((result
= Openpty(&ptyfd
, &ttyfd
, ptyname
, NULL
, NULL
)) < 0) {
143 Error4("openpty(%p, %p, %p, NULL, NULL): %s",
144 &ptyfd
, &ttyfd
, ptyname
, strerror(errno
));
147 Notice1("PTY is %s", ptyname
);
149 #endif /* HAVE_OPENPTY */
151 if (!retropt_string(opts
, OPT_SYMBOLIC_LINK
, &linkname
)) {
152 if (Unlink(linkname
) < 0 && errno
!= ENOENT
) {
153 Error2("unlink(\"%s\"): %s", linkname
, strerror(errno
));
155 if (Symlink(ptyname
, linkname
) < 0) {
156 Error3("symlink(\"%s\", \"%s\"): %s",
157 ptyname
, linkname
, strerror(errno
));
159 if (opt_unlink_close
) {
160 if ((xfd
->stream
.unlink_close
= strdup(linkname
)) == NULL
) {
161 Error1("strdup(\"%s\"): out of memory", linkname
);
163 xfd
->stream
.opt_unlink_close
= true;
167 applyopts_named(ptyname
, opts
, PH_PASTOPEN
);
168 applyopts_named(ptyname
, opts
, PH_FD
);
170 applyopts_cloexec(ptyfd
, opts
);/*!*/
171 xfd
->stream
.dtype
= XIODATA_PTY
;
173 applyopts(ptyfd
, opts
, PH_FD
);
176 /* special handling of user-late etc.; with standard behaviour (up to
177 1.7.1.1) they affected /dev/ptmx instead of /dev/pts/N */
178 uid_t uid
= -1, gid
= -1;
182 dont
= retropt_uid(opts
, OPT_USER_LATE
, &uid
);
183 dont
&= retropt_gid(opts
, OPT_GROUP_LATE
, &gid
);
186 if (Chown(ptyname
, uid
, gid
) < 0) {
187 Error4("chown(\"%s\", %d, %d): %s",
188 ptyname
, uid
, gid
, strerror(errno
));
192 if (retropt_mode(opts
, OPT_PERM_LATE
, &perm
) == 0) {
193 if (Chmod(ptyname
, perm
) < 0) {
194 Error3("chmod(\"%s\", %03o): %s",
195 ptyname
, perm
, strerror(errno
));
201 xfd
->stream
.fd
= ptyfd
;
202 applyopts(ptyfd
, opts
, PH_LATE
);
203 if (applyopts_single(&xfd
->stream
, opts
, PH_LATE
) < 0) return -1;
206 /* if you can and wish: */
208 /* try to wait until someone opens the slave side of the pty */
209 /* we want to get a HUP (hangup) condition on the pty */
210 #if HAVE_DEV_PTMX || HAVE_DEV_PTC
212 ttyfd
= Open(tn
, O_RDWR
|O_NOCTTY
, 0620);
220 #endif /* HAVE_OPENPTY */
222 /* now we poll until the HUP vanishes - this indicates a slave conn. */
226 ufd
.events
= (POLLHUP
);
227 if (Poll(&ufd
, 1, 0) < 0) {
228 Error3("poll({%d, 0x%04hu,}, 1, 0): %s",
229 ufd
.fd
, ufd
.events
, strerror(errno
));
230 /*! close something */
233 if (!(ufd
.revents
& POLLHUP
)) {
236 Nanosleep(&pollintv
, NULL
);
240 #endif /* HAVE_POLL */
244 #endif /* WITH_PTY */