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 /*      Copyright (c) 1988 AT&T     */
  28 /*        All Rights Reserved   */
  29 
  30 #pragma ident   "%Z%%M% %I%     %E% SMI"
  31 
  32 #pragma weak _ptsname = ptsname
  33 #pragma weak _grantpt = grantpt
  34 #pragma weak _unlockpt = unlockpt
  35 
  36 #include "lint.h"
  37 #include "libc.h"
  38 #include "mtlib.h"
  39 #include <sys/types.h>
  40 #include <signal.h>
  41 #include <sys/param.h>
  42 #include <sys/mkdev.h>
  43 #include <sys/stream.h>
  44 #include <sys/stropts.h>
  45 #include <sys/wait.h>
  46 #include <sys/signal.h>
  47 #include <errno.h>
  48 #include <fcntl.h>
  49 #include <sys/stat.h>
  50 #include <sys/ptms.h>
  51 #include <string.h>
  52 #include <stdlib.h>
  53 #include <unistd.h>
  54 #include <wait.h>
  55 #include <spawn.h>
  56 #include <grp.h>
  57 #include "tsd.h"
  58 
  59 #define PTSNAME "/dev/pts/"             /* slave name */
  60 #define PTLEN   32                      /* slave name length */
  61 #define DEFAULT_TTY_GROUP       "tty"   /* slave device group owner */
  62 
  63 static void itoa(int, char *);
  64 
  65 /*
  66  *  Check that fd argument is a file descriptor of an opened master.
  67  *  Do this by sending an ISPTM ioctl message down stream. Ioctl()
  68  *  will fail if:(1) fd is not a valid file descriptor.(2) the file
  69  *  represented by fd does not understand ISPTM(not a master device).
  70  *  If we have a valid master, get its minor number via fstat().
  71  *  Concatenate it to PTSNAME and return it as the name of the slave
  72  *  device.
  73  */
  74 static dev_t
  75 ptsdev(int fd)
  76 {
  77         struct stat64 status;
  78         struct strioctl istr;
  79 
  80         istr.ic_cmd = ISPTM;
  81         istr.ic_len = 0;
  82         istr.ic_timout = 0;
  83         istr.ic_dp = NULL;
  84 
  85         if (ioctl(fd, I_STR, &istr) < 0 || fstat64(fd, &status) < 0)
  86                 return (NODEV);
  87 
  88         return (minor(status.st_rdev));
  89 }
  90 
  91 char *
  92 ptsname(int fd)
  93 {
  94         dev_t dev;
  95         char *sname;
  96 
  97         if ((dev = ptsdev(fd)) == NODEV)
  98                 return (NULL);
  99 
 100         sname = tsdalloc(_T_PTSNAME, PTLEN, NULL);
 101         if (sname == NULL)
 102                 return (NULL);
 103         (void) strcpy(sname, PTSNAME);
 104         itoa(dev, sname + strlen(PTSNAME));
 105 
 106         /*
 107          * This lookup will create the /dev/pts node (if the corresponding
 108          * pty exists.
 109          */
 110         if (access(sname, F_OK) ==  0)
 111                 return (sname);
 112 
 113         return (NULL);
 114 }
 115 
 116 /*
 117  * Send an ioctl down to the master device requesting the
 118  * master/slave pair be unlocked.
 119  */
 120 int
 121 unlockpt(int fd)
 122 {
 123         struct strioctl istr;
 124 
 125         istr.ic_cmd = UNLKPT;
 126         istr.ic_len = 0;
 127         istr.ic_timout = 0;
 128         istr.ic_dp = NULL;
 129 
 130         if (ioctl(fd, I_STR, &istr) < 0)
 131                 return (-1);
 132 
 133         return (0);
 134 }
 135 
 136 int
 137 grantpt(int fd)
 138 {
 139         struct strioctl istr;
 140         pt_own_t pto;
 141         struct group *gr_name;
 142 
 143         /* validate the file descriptor before proceeding */
 144         if (ptsdev(fd) == NODEV)
 145                 return (-1);
 146 
 147         pto.pto_ruid = getuid();
 148 
 149         gr_name = getgrnam(DEFAULT_TTY_GROUP);
 150         if (gr_name)
 151                 pto.pto_rgid = gr_name->gr_gid;
 152         else
 153                 pto.pto_rgid = getgid();
 154 
 155         istr.ic_cmd = OWNERPT;
 156         istr.ic_len = sizeof (pt_own_t);
 157         istr.ic_timout = 0;
 158         istr.ic_dp = (char *)&pto;
 159 
 160         if (ioctl(fd, I_STR, &istr) != 0) {
 161                 errno = EACCES;
 162                 return (-1);
 163         }
 164 
 165         return (0);
 166 }
 167 
 168 /*
 169  * Send an ioctl down to the master device requesting the master/slave pair
 170  * be assigned to the given zone.
 171  */
 172 int
 173 zonept(int fd, zoneid_t zoneid)
 174 {
 175         struct strioctl istr;
 176 
 177         istr.ic_cmd = ZONEPT;
 178         istr.ic_len = sizeof (zoneid);
 179         istr.ic_timout = 0;
 180         istr.ic_dp = (char *)&zoneid;
 181 
 182         if (ioctl(fd, I_STR, &istr) != 0) {
 183                 return (-1);
 184         }
 185         return (0);
 186 }
 187 
 188 
 189 static void
 190 itoa(int i, char *ptr)
 191 {
 192         int dig = 0;
 193         int tempi;
 194 
 195         tempi = i;
 196         do {
 197                 dig++;
 198                 tempi /= 10;
 199         } while (tempi);
 200 
 201         ptr += dig;
 202         *ptr = '\0';
 203         while (--dig >= 0) {
 204                 *(--ptr) = i % 10 + '0';
 205                 i /= 10;
 206         }
 207 }
 208 
 209 
 210 /*
 211  * added for SUSv3 standard
 212  *
 213  * Open a pseudo-terminal device.  External interface.
 214  */
 215 
 216 int
 217 posix_openpt(int oflag)
 218 {
 219         return (open("/dev/ptmx", oflag));
 220 }