1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Copyright 2020 OmniOS Community Edition (OmniOSce) Association. 29 */ 30 31 /* Copyright (c) 1988 AT&T */ 32 /* All Rights Reserved */ 33 34 #pragma weak _ptsname = ptsname 35 #pragma weak _grantpt = grantpt 36 #pragma weak _unlockpt = unlockpt 37 38 #include "lint.h" 39 #include "libc.h" 40 #include "mtlib.h" 41 #include <sys/types.h> 42 #include <signal.h> 43 #include <sys/param.h> 44 #include <sys/mkdev.h> 45 #include <sys/stream.h> 46 #include <sys/stropts.h> 47 #include <sys/wait.h> 48 #include <sys/signal.h> 49 #include <errno.h> 50 #include <fcntl.h> 51 #include <sys/stat.h> 52 #include <sys/ptms.h> 53 #include <string.h> 54 #include <stdlib.h> 55 #include <unistd.h> 56 #include <wait.h> 57 #include <spawn.h> 58 #include <grp.h> 59 #include "tsd.h" 60 61 #define PTSNAME "/dev/pts/" /* slave name */ 62 #define PTLEN 32 /* slave name length */ 63 #define DEFAULT_TTY_GROUP "tty" /* slave device group owner */ 64 65 static void itoa(int, char *); 66 67 /* 68 * Check that fd argument is a file descriptor of an opened master. 69 * Do this by sending an ISPTM ioctl message down stream. Ioctl() 70 * will fail if:(1) fd is not a valid file descriptor.(2) the file 71 * represented by fd does not understand ISPTM(not a master device). 72 * If we have a valid master, get its minor number via fstat(). 73 * Concatenate it to PTSNAME and return it as the name of the slave 74 * device. 75 */ 76 static dev_t 77 ptsdev(int fd) 78 { 79 struct stat64 status; 80 struct strioctl istr; 81 82 istr.ic_cmd = ISPTM; 83 istr.ic_len = 0; 84 istr.ic_timout = 0; 85 istr.ic_dp = NULL; 86 87 if (ioctl(fd, I_STR, &istr) < 0 || fstat64(fd, &status) < 0) 88 return (NODEV); 89 90 return (minor(status.st_rdev)); 91 } 92 93 char * 94 ptsname(int fd) 95 { 96 dev_t dev; 97 char *sname; 98 99 if ((dev = ptsdev(fd)) == NODEV) 100 return (NULL); 101 102 sname = tsdalloc(_T_PTSNAME, PTLEN, NULL); 103 if (sname == NULL) 104 return (NULL); 105 (void) strcpy(sname, PTSNAME); 106 itoa(dev, sname + strlen(PTSNAME)); 107 108 /* 109 * This lookup will create the /dev/pts node (if the corresponding 110 * pty exists. 111 */ 112 if (access(sname, F_OK) == 0) 113 return (sname); 114 115 return (NULL); 116 } 117 118 /* 119 * Send an ioctl down to the master device requesting the 120 * master/slave pair be unlocked. 121 */ 122 int 123 unlockpt(int fd) 124 { 125 struct strioctl istr; 126 127 istr.ic_cmd = UNLKPT; 128 istr.ic_len = 0; 129 istr.ic_timout = 0; 130 istr.ic_dp = NULL; 131 132 if (ioctl(fd, I_STR, &istr) < 0) 133 return (-1); 134 135 return (0); 136 } 137 138 /* 139 * XPG4v2 requires that open of a slave pseudo terminal device 140 * provides the process with an interface that is identical to 141 * the terminal interface. 142 * 143 * To satisfy this, in strict XPG4v2 mode, this routine also sends 144 * a message down the stream that sets a flag in the kernel module 145 * so that additional actions are performed when opening an 146 * associated slave PTY device. When this happens, modules are 147 * automatically pushed onto the stream to provide terminal 148 * semantics and those modules are then informed that they should 149 * behave in strict XPG4v2 mode which modifies their behaviour. In 150 * particular, in strict XPG4v2 mode, empty blocks will be sent up 151 * the master side of the stream rather than being suppressed. 152 * 153 * Most applications do not expect this behaviour so it is only 154 * enabled for programs compiled in strict XPG4v2 mode (see 155 * stdlib.h). 156 */ 157 int 158 __unlockpt_xpg4(int fd) 159 { 160 int ret; 161 162 if ((ret = unlockpt(fd)) == 0) { 163 struct strioctl istr; 164 165 istr.ic_cmd = PTSSTTY; 166 istr.ic_len = 0; 167 istr.ic_timout = 0; 168 istr.ic_dp = NULL; 169 170 if (ioctl(fd, I_STR, &istr) < 0) 171 ret = -1; 172 } 173 174 return (ret); 175 } 176 177 int 178 grantpt(int fd) 179 { 180 struct strioctl istr; 181 pt_own_t pto; 182 struct group *gr_name; 183 184 /* validate the file descriptor before proceeding */ 185 if (ptsdev(fd) == NODEV) 186 return (-1); 187 188 pto.pto_ruid = getuid(); 189 190 gr_name = getgrnam(DEFAULT_TTY_GROUP); 191 if (gr_name) 192 pto.pto_rgid = gr_name->gr_gid; 193 else 194 pto.pto_rgid = getgid(); 195 196 istr.ic_cmd = OWNERPT; 197 istr.ic_len = sizeof (pt_own_t); 198 istr.ic_timout = 0; 199 istr.ic_dp = (char *)&pto; 200 201 if (ioctl(fd, I_STR, &istr) != 0) { 202 errno = EACCES; 203 return (-1); 204 } 205 206 return (0); 207 } 208 209 /* 210 * Send an ioctl down to the master device requesting the master/slave pair 211 * be assigned to the given zone. 212 */ 213 int 214 zonept(int fd, zoneid_t zoneid) 215 { 216 struct strioctl istr; 217 218 istr.ic_cmd = ZONEPT; 219 istr.ic_len = sizeof (zoneid); 220 istr.ic_timout = 0; 221 istr.ic_dp = (char *)&zoneid; 222 223 if (ioctl(fd, I_STR, &istr) != 0) { 224 return (-1); 225 } 226 return (0); 227 } 228 229 230 static void 231 itoa(int i, char *ptr) 232 { 233 int dig = 0; 234 int tempi; 235 236 tempi = i; 237 do { 238 dig++; 239 tempi /= 10; 240 } while (tempi); 241 242 ptr += dig; 243 *ptr = '\0'; 244 while (--dig >= 0) { 245 *(--ptr) = i % 10 + '0'; 246 i /= 10; 247 } 248 } 249 250 251 /* 252 * added for SUSv3 standard 253 * 254 * Open a pseudo-terminal device. External interface. 255 */ 256 257 int 258 posix_openpt(int oflag) 259 { 260 return (open("/dev/ptmx", oflag)); 261 } 262