1/* 2 * Copyright (c) 1988, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#if defined(LIBC_SCCS) && !defined(lint) 35static char sccsid[] = "@(#)ttyname.c 8.2 (Berkeley) 1/27/94"; 36#endif /* LIBC_SCCS and not lint */ 37#include <sys/cdefs.h> 38__FBSDID("$FreeBSD: src/lib/libc/gen/ttyname.c,v 1.16 2004/01/06 18:26:14 nectar Exp $"); 39 40#include "namespace.h" 41#include <sys/types.h> 42#include <sys/stat.h> 43#include <fcntl.h> 44#include <dirent.h> 45#include <stdlib.h> 46#include <termios.h> 47#include <unistd.h> 48#include <string.h> 49#include <paths.h> 50#include <pthread.h> 51#include <errno.h> 52#include "un-namespace.h" 53 54#include "libc_private.h" 55 56#ifndef BUILDING_VARIANT 57static pthread_once_t ttyname_buf_control = PTHREAD_ONCE_INIT; 58static char *buf = NULL; 59static char *ttyname_threaded(int fd); 60static char *ttyname_unthreaded(int fd); 61 62static pthread_mutex_t ttyname_lock = PTHREAD_MUTEX_INITIALIZER; 63static pthread_key_t ttyname_key; 64static int ttyname_init = 0; 65 66char * 67ttyname(int fd) 68{ 69 char *ret; 70 71 if (__isthreaded == 0) 72 ret = ttyname_unthreaded(fd); 73 else 74 ret = ttyname_threaded(fd); 75 return (ret); 76} 77#endif /* !BUILDING_VARIANT */ 78 79#if __DARWIN_UNIX03 80int 81#else /* !__DARWIN_UNIX03 */ 82char * 83#endif /* __DARWIN_UNIX03 */ 84ttyname_r(int fd, char *thrbuf, size_t len) 85{ 86 struct stat sb; 87 88#if __DARWIN_UNIX03 89 if (_fstat(fd, &sb) < 0) 90 return (EBADF); 91 /* Must be a terminal. */ 92 if (!isatty(fd)) 93 return (ENOTTY); 94 /* Must be a character device. */ 95 if (!S_ISCHR(sb.st_mode)) 96 return (ENOTTY); 97 /* Must have enough room */ 98 if (len <= sizeof(_PATH_DEV)) 99 return (ERANGE); 100#else /* !__DARWIN_UNIX03 */ 101 /* Must be a terminal. */ 102 if (!isatty(fd)) 103 return (NULL); 104 /* Must be a character device. */ 105 if (_fstat(fd, &sb)) 106 return (NULL); 107 if (!S_ISCHR(sb.st_mode)) { 108 errno = ENOTTY; 109 return (NULL); 110 } 111 /* Must have enough room */ 112 if (len <= sizeof(_PATH_DEV)) { 113 errno = ERANGE; 114 return (NULL); 115 } 116#endif /* __DARWIN_UNIX03 */ 117 118 strlcpy(thrbuf, _PATH_DEV, len); 119 if (devname_r(sb.st_rdev, S_IFCHR, 120 thrbuf + strlen(thrbuf), len - strlen(thrbuf)) == NULL) 121#if __DARWIN_UNIX03 122 return (ERANGE); 123 return (0); 124#else /* !__DARWIN_UNIX03 */ 125 { 126 errno = ERANGE; 127 return (NULL); 128 } 129 return (thrbuf); 130#endif /* __DARWIN_UNIX03 */ 131} 132 133#ifndef BUILDING_VARIANT 134static char * 135ttyname_threaded(int fd) 136{ 137 char *buf; 138 139 if (ttyname_init == 0) { 140 _pthread_mutex_lock(&ttyname_lock); 141 if (ttyname_init == 0) { 142 /* __PTK_LIBC_TTYNAME_KEY */ 143 ttyname_key = __LIBC_PTHREAD_KEY_TTYNAME; 144 if (pthread_key_init_np(ttyname_key, free)) { 145 int save = errno; 146 _pthread_mutex_unlock(&ttyname_lock); 147 errno = save; 148 return (NULL); 149 } 150 ttyname_init = 1; 151 } 152 _pthread_mutex_unlock(&ttyname_lock); 153 } 154 155 /* Must have thread specific data field to put data */ 156 if ((buf = _pthread_getspecific(ttyname_key)) == NULL) { 157 if ((buf = malloc(sizeof(_PATH_DEV) + MAXNAMLEN)) != NULL) { 158 if (_pthread_setspecific(ttyname_key, buf) != 0) { 159 int save = errno; 160 free(buf); 161 errno = save; 162 return (NULL); 163 } 164 } else { 165 return (NULL); 166 } 167 } 168#if __DARWIN_UNIX03 169 return (ttyname_r(fd, buf, sizeof(_PATH_DEV) + MAXNAMLEN) == 0 ? buf : NULL); 170#else /* !__DARWIN_UNIX03 */ 171 return (ttyname_r(fd, buf, sizeof(_PATH_DEV) + MAXNAMLEN)); 172#endif /* __DARWIN_UNIX03 */ 173} 174 175static void 176ttyname_buf_allocate(void) 177{ 178 buf = malloc(sizeof(_PATH_DEV) + MAXNAMLEN); 179} 180 181static char * 182ttyname_unthreaded(int fd) 183{ 184 struct stat sb; 185 struct termios ttyb; 186 187 /* Must be a terminal. */ 188 if (tcgetattr(fd, &ttyb) < 0) 189 return (NULL); 190 /* Must be a character device. */ 191 if (_fstat(fd, &sb)) 192 return (NULL); 193 if (!S_ISCHR(sb.st_mode)) { 194 errno = ENOTTY; 195 return (NULL); 196 } 197 198 if (pthread_once(&ttyname_buf_control, ttyname_buf_allocate) 199 || !buf) { 200 errno = ENOMEM; 201 return (NULL); 202 } 203 204 strlcpy(buf, _PATH_DEV, sizeof(_PATH_DEV) + MAXNAMLEN); 205 if (devname_r(sb.st_rdev, S_IFCHR, 206 buf + strlen(buf), sizeof(_PATH_DEV) + MAXNAMLEN - strlen(buf)) == NULL) { 207 errno = ERANGE; 208 return (NULL); 209 } 210 return (buf); 211} 212#endif /* !BUILDING_VARIANT */ 213