Home | History | Annotate | Download | only in sys
      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 #include "lint.h"
     33 #include <sys/mkdev.h>
     34 #include <limits.h>
     35 #include <stdarg.h>
     36 #include <unistd.h>
     37 #include <strings.h>
     38 #include <errno.h>
     39 #include <sys/stat.h>
     40 #include <sys/stropts.h>
     41 #include <sys/stream.h>
     42 #include <sys/ptms.h>
     43 #include "libc.h"
     44 
     45 #if !defined(_LP64)
     46 extern int __open64_syscall(const char *fname, int oflag, mode_t mode);
     47 #endif
     48 
     49 extern int __open_syscall(const char *fname, int oflag, mode_t mode);
     50 
     51 static void push_module(int fd);
     52 static int isptsfd(int fd);
     53 static void itoa(int i, char *ptr);
     54 
     55 int
     56 __open(const char *fname, int oflag, ...)
     57 {
     58 	mode_t mode;
     59 	int fd;
     60 	va_list ap;
     61 
     62 	va_start(ap, oflag);
     63 	mode = va_arg(ap, mode_t);
     64 	va_end(ap);
     65 
     66 	/*
     67 	 * XPG4v2 requires that open of a slave pseudo terminal device
     68 	 * provides the process with an interface that is identical to
     69 	 * the terminal interface. For a more detailed discussion,
     70 	 * see bugid 4025044.
     71 	 */
     72 	fd = __open_syscall(fname, oflag, mode);
     73 	if (libc__xpg4 != 0 && fd >= 0 && isptsfd(fd))
     74 		push_module(fd);
     75 	return (fd);
     76 }
     77 
     78 #if !defined(_LP64)
     79 /*
     80  * The 32-bit APIs to large files require this interposition.
     81  * The 64-bit APIs just fall back to __open() above.
     82  */
     83 int
     84 __open64(const char *fname, int oflag, ...)
     85 {
     86 	mode_t mode;
     87 	int fd;
     88 	va_list ap;
     89 
     90 	va_start(ap, oflag);
     91 	mode = va_arg(ap, mode_t);
     92 	va_end(ap);
     93 
     94 	/*
     95 	 * XPG4v2 requires that open of a slave pseudo terminal device
     96 	 * provides the process with an interface that is identical to
     97 	 * the terminal interface. For a more detailed discussion,
     98 	 * see bugid 4025044.
     99 	 */
    100 	fd = __open64_syscall(fname, oflag, mode);
    101 	if (libc__xpg4 != 0 && fd >= 0 && isptsfd(fd))
    102 		push_module(fd);
    103 	return (fd);
    104 }
    105 #endif	/* !_LP64 */
    106 
    107 /*
    108  * Check if the file matches an entry in the /dev/pts directory.
    109  * Be careful to preserve errno.
    110  */
    111 static int
    112 isptsfd(int fd)
    113 {
    114 	char buf[TTYNAME_MAX];
    115 	char *str1 = buf;
    116 	const char *str2 = "/dev/pts/";
    117 	struct stat64 fsb, stb;
    118 	int oerrno = errno;
    119 	int rval = 0;
    120 
    121 	if (fstat64(fd, &fsb) == 0 && S_ISCHR(fsb.st_mode)) {
    122 		/*
    123 		 * Do this without strcpy() or strlen(),
    124 		 * to avoid invoking the dynamic linker.
    125 		 */
    126 		while (*str2 != '\0')
    127 			*str1++ = *str2++;
    128 		/*
    129 		 * Inline version of minor(dev), to avoid the dynamic linker.
    130 		 */
    131 		itoa(fsb.st_rdev & MAXMIN, str1);
    132 		if (stat64(buf, &stb) == 0)
    133 			rval = (stb.st_rdev == fsb.st_rdev);
    134 	}
    135 	errno = oerrno;
    136 	return (rval);
    137 }
    138 
    139 /*
    140  * Converts a number to a string (null terminated).
    141  */
    142 static void
    143 itoa(int i, char *ptr)
    144 {
    145 	int dig = 0;
    146 	int tempi;
    147 
    148 	tempi = i;
    149 	do {
    150 		dig++;
    151 		tempi /= 10;
    152 	} while (tempi);
    153 
    154 	ptr += dig;
    155 	*ptr = '\0';
    156 	while (--dig >= 0) {
    157 		*(--ptr) = i % 10 + '0';
    158 		i /= 10;
    159 	}
    160 }
    161 
    162 /*
    163  * Push modules to provide tty semantics
    164  */
    165 static void
    166 push_module(int fd)
    167 {
    168 	struct strioctl istr;
    169 	int oerrno = errno;
    170 
    171 	istr.ic_cmd = PTSSTTY;
    172 	istr.ic_len = 0;
    173 	istr.ic_timout = 0;
    174 	istr.ic_dp = NULL;
    175 	if (ioctl(fd, I_STR, &istr) != -1) {
    176 		(void) ioctl(fd, __I_PUSH_NOCTTY, "ptem");
    177 		(void) ioctl(fd, __I_PUSH_NOCTTY, "ldterm");
    178 		(void) ioctl(fd, __I_PUSH_NOCTTY, "ttcompat");
    179 		istr.ic_cmd = PTSSTTY;
    180 		istr.ic_len = 0;
    181 		istr.ic_timout = 0;
    182 		istr.ic_dp = NULL;
    183 		(void) ioctl(fd, I_STR, &istr);
    184 	}
    185 	errno = oerrno;
    186 }
    187