1*bf198cc6Smillert /* $OpenBSD: posix_pty.c,v 1.3 2019/01/25 00:19:25 millert Exp $ */
28d2ec7eaSmillert
38d2ec7eaSmillert /*
4*bf198cc6Smillert * Copyright (c) 2012 Todd C. Miller <millert@openbsd.org>
58d2ec7eaSmillert *
68d2ec7eaSmillert * Permission to use, copy, modify, and distribute this software for any
78d2ec7eaSmillert * purpose with or without fee is hereby granted, provided that the above
88d2ec7eaSmillert * copyright notice and this permission notice appear in all copies.
98d2ec7eaSmillert *
108d2ec7eaSmillert * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
118d2ec7eaSmillert * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
128d2ec7eaSmillert * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
138d2ec7eaSmillert * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
148d2ec7eaSmillert * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
158d2ec7eaSmillert * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
168d2ec7eaSmillert * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
178d2ec7eaSmillert */
188d2ec7eaSmillert
198d2ec7eaSmillert #include <sys/types.h>
208d2ec7eaSmillert #include <sys/ioctl.h>
218d2ec7eaSmillert #include <sys/stat.h>
228d2ec7eaSmillert #include <sys/tty.h>
238d2ec7eaSmillert #include <errno.h>
248d2ec7eaSmillert #include <fcntl.h>
258d2ec7eaSmillert #include <paths.h>
268d2ec7eaSmillert #include <stddef.h>
278d2ec7eaSmillert #include <stdlib.h>
288d2ec7eaSmillert #include <string.h>
298d2ec7eaSmillert #include <unistd.h>
308d2ec7eaSmillert
318d2ec7eaSmillert int
posix_openpt(int oflag)328d2ec7eaSmillert posix_openpt(int oflag)
338d2ec7eaSmillert {
348d2ec7eaSmillert struct ptmget ptm;
358d2ec7eaSmillert int fd, mfd = -1;
368d2ec7eaSmillert
378d2ec7eaSmillert /* User must specify O_RDWR in oflag. */
38dc519336Sguenther if ((oflag & O_ACCMODE) != O_RDWR ||
39dc519336Sguenther (oflag & ~(O_ACCMODE | O_NOCTTY)) != 0) {
408d2ec7eaSmillert errno = EINVAL;
418d2ec7eaSmillert return -1;
428d2ec7eaSmillert }
438d2ec7eaSmillert
448d2ec7eaSmillert /* Get pty master and slave (this API only uses the master). */
458d2ec7eaSmillert fd = open(PATH_PTMDEV, O_RDWR);
468d2ec7eaSmillert if (fd != -1) {
478d2ec7eaSmillert if (ioctl(fd, PTMGET, &ptm) != -1) {
488d2ec7eaSmillert close(ptm.sfd);
498d2ec7eaSmillert mfd = ptm.cfd;
508d2ec7eaSmillert }
518d2ec7eaSmillert close(fd);
528d2ec7eaSmillert }
538d2ec7eaSmillert
548d2ec7eaSmillert return mfd;
558d2ec7eaSmillert }
568d2ec7eaSmillert
578d2ec7eaSmillert /*
588d2ec7eaSmillert * Look up the name of the specified pty master fd.
598d2ec7eaSmillert * Note that the name returned does *not* include the /dev/ prefix.
608d2ec7eaSmillert * Returns the name on success and NULL on error, setting errno.
618d2ec7eaSmillert */
628d2ec7eaSmillert static const char *
ptmname(int mfd)638d2ec7eaSmillert ptmname(int mfd)
648d2ec7eaSmillert {
658d2ec7eaSmillert struct stat sb;
668d2ec7eaSmillert const char *name;
678d2ec7eaSmillert
688d2ec7eaSmillert /* Make sure it is a pty master. */
698d2ec7eaSmillert if (fstat(mfd, &sb) != 0)
708d2ec7eaSmillert return NULL;
718d2ec7eaSmillert if (!S_ISCHR(sb.st_mode)) {
728d2ec7eaSmillert errno = EINVAL;
738d2ec7eaSmillert return NULL;
748d2ec7eaSmillert }
758d2ec7eaSmillert name = devname(sb.st_rdev, S_IFCHR);
768d2ec7eaSmillert if (strncmp(name, "pty", 3) != 0) {
778d2ec7eaSmillert errno = EINVAL;
788d2ec7eaSmillert return NULL;
798d2ec7eaSmillert }
808d2ec7eaSmillert return name;
818d2ec7eaSmillert }
828d2ec7eaSmillert
838d2ec7eaSmillert /*
848d2ec7eaSmillert * The PTMGET ioctl handles the mode and owner for us.
858d2ec7eaSmillert */
868d2ec7eaSmillert int
grantpt(int mfd)878d2ec7eaSmillert grantpt(int mfd)
888d2ec7eaSmillert {
898d2ec7eaSmillert return ptmname(mfd) ? 0 : -1;
908d2ec7eaSmillert }
918d2ec7eaSmillert
928d2ec7eaSmillert /*
938d2ec7eaSmillert * The PTMGET ioctl unlocks the pty master and slave for us.
948d2ec7eaSmillert */
958d2ec7eaSmillert int
unlockpt(int mfd)968d2ec7eaSmillert unlockpt(int mfd)
978d2ec7eaSmillert {
988d2ec7eaSmillert return ptmname(mfd) ? 0 : -1;
998d2ec7eaSmillert }
1008d2ec7eaSmillert
1018d2ec7eaSmillert /*
1028d2ec7eaSmillert * Look up the path of the slave pty that corresponds to the master fd.
1038d2ec7eaSmillert * Returns the path if successful or NULL on error.
1048d2ec7eaSmillert */
1058d2ec7eaSmillert char *
ptsname(int mfd)1068d2ec7eaSmillert ptsname(int mfd)
1078d2ec7eaSmillert {
1088d2ec7eaSmillert const char *master;
1098d2ec7eaSmillert static char slave[sizeof(((struct ptmget *)NULL)->sn)];
1108d2ec7eaSmillert
1118d2ec7eaSmillert if ((master = ptmname(mfd)) == NULL)
1128d2ec7eaSmillert return NULL;
1138d2ec7eaSmillert
1148d2ec7eaSmillert /* Add /dev/ prefix and convert "pty" to "tty". */
1158d2ec7eaSmillert strlcpy(slave, _PATH_DEV, sizeof(slave));
1168d2ec7eaSmillert strlcat(slave, master, sizeof(slave));
1178d2ec7eaSmillert slave[sizeof(_PATH_DEV) - 1] = 't';
1188d2ec7eaSmillert
1198d2ec7eaSmillert return slave;
1208d2ec7eaSmillert }
121