1 /* $OpenBSD: posix_pty.c,v 1.3 2019/01/25 00:19:25 millert Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Todd C. Miller <millert@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/ioctl.h> 21 #include <sys/stat.h> 22 #include <sys/tty.h> 23 #include <errno.h> 24 #include <fcntl.h> 25 #include <paths.h> 26 #include <stddef.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 31 int 32 posix_openpt(int oflag) 33 { 34 struct ptmget ptm; 35 int fd, mfd = -1; 36 37 /* User must specify O_RDWR in oflag. */ 38 if ((oflag & O_ACCMODE) != O_RDWR || 39 (oflag & ~(O_ACCMODE | O_NOCTTY)) != 0) { 40 errno = EINVAL; 41 return -1; 42 } 43 44 /* Get pty master and slave (this API only uses the master). */ 45 fd = open(PATH_PTMDEV, O_RDWR); 46 if (fd != -1) { 47 if (ioctl(fd, PTMGET, &ptm) != -1) { 48 close(ptm.sfd); 49 mfd = ptm.cfd; 50 } 51 close(fd); 52 } 53 54 return mfd; 55 } 56 57 /* 58 * Look up the name of the specified pty master fd. 59 * Note that the name returned does *not* include the /dev/ prefix. 60 * Returns the name on success and NULL on error, setting errno. 61 */ 62 static const char * 63 ptmname(int mfd) 64 { 65 struct stat sb; 66 const char *name; 67 68 /* Make sure it is a pty master. */ 69 if (fstat(mfd, &sb) != 0) 70 return NULL; 71 if (!S_ISCHR(sb.st_mode)) { 72 errno = EINVAL; 73 return NULL; 74 } 75 name = devname(sb.st_rdev, S_IFCHR); 76 if (strncmp(name, "pty", 3) != 0) { 77 errno = EINVAL; 78 return NULL; 79 } 80 return name; 81 } 82 83 /* 84 * The PTMGET ioctl handles the mode and owner for us. 85 */ 86 int 87 grantpt(int mfd) 88 { 89 return ptmname(mfd) ? 0 : -1; 90 } 91 92 /* 93 * The PTMGET ioctl unlocks the pty master and slave for us. 94 */ 95 int 96 unlockpt(int mfd) 97 { 98 return ptmname(mfd) ? 0 : -1; 99 } 100 101 /* 102 * Look up the path of the slave pty that corresponds to the master fd. 103 * Returns the path if successful or NULL on error. 104 */ 105 char * 106 ptsname(int mfd) 107 { 108 const char *master; 109 static char slave[sizeof(((struct ptmget *)NULL)->sn)]; 110 111 if ((master = ptmname(mfd)) == NULL) 112 return NULL; 113 114 /* Add /dev/ prefix and convert "pty" to "tty". */ 115 strlcpy(slave, _PATH_DEV, sizeof(slave)); 116 strlcat(slave, master, sizeof(slave)); 117 slave[sizeof(_PATH_DEV) - 1] = 't'; 118 119 return slave; 120 } 121