1 /* $OpenBSD: posix_pty.c,v 1.1 2012/12/03 20:08:33 millert Exp $ */ 2 3 /* 4 * Copyright (c) 2012 Todd C. Miller <Todd.Miller@courtesan.com> 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_RDWR)) { 39 errno = EINVAL; 40 return -1; 41 } 42 43 /* Get pty master and slave (this API only uses the master). */ 44 fd = open(PATH_PTMDEV, O_RDWR); 45 if (fd != -1) { 46 if (ioctl(fd, PTMGET, &ptm) != -1) { 47 close(ptm.sfd); 48 mfd = ptm.cfd; 49 } 50 close(fd); 51 } 52 53 return mfd; 54 } 55 56 /* 57 * Look up the name of the specified pty master fd. 58 * Note that the name returned does *not* include the /dev/ prefix. 59 * Returns the name on success and NULL on error, setting errno. 60 */ 61 static const char * 62 ptmname(int mfd) 63 { 64 struct stat sb; 65 const char *name; 66 67 /* Make sure it is a pty master. */ 68 if (fstat(mfd, &sb) != 0) 69 return NULL; 70 if (!S_ISCHR(sb.st_mode)) { 71 errno = EINVAL; 72 return NULL; 73 } 74 name = devname(sb.st_rdev, S_IFCHR); 75 if (strncmp(name, "pty", 3) != 0) { 76 errno = EINVAL; 77 return NULL; 78 } 79 return name; 80 } 81 82 /* 83 * The PTMGET ioctl handles the mode and owner for us. 84 */ 85 int 86 grantpt(int mfd) 87 { 88 return ptmname(mfd) ? 0 : -1; 89 } 90 91 /* 92 * The PTMGET ioctl unlocks the pty master and slave for us. 93 */ 94 int 95 unlockpt(int mfd) 96 { 97 return ptmname(mfd) ? 0 : -1; 98 } 99 100 /* 101 * Look up the path of the slave pty that corresponds to the master fd. 102 * Returns the path if successful or NULL on error. 103 */ 104 char * 105 ptsname(int mfd) 106 { 107 const char *master; 108 static char slave[sizeof(((struct ptmget *)NULL)->sn)]; 109 110 if ((master = ptmname(mfd)) == NULL) 111 return NULL; 112 113 /* Add /dev/ prefix and convert "pty" to "tty". */ 114 strlcpy(slave, _PATH_DEV, sizeof(slave)); 115 strlcat(slave, master, sizeof(slave)); 116 slave[sizeof(_PATH_DEV) - 1] = 't'; 117 118 return slave; 119 } 120