ttyname.c revision 90045
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: head/lib/libc/gen/ttyname.c 90045 2002-02-01 01:32:19Z obrien $");
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 "un-namespace.h"
52
53#include <db.h>
54#include "libc_private.h"
55
56static char buf[sizeof(_PATH_DEV) + MAXNAMLEN] = _PATH_DEV;
57static char *oldttyname(int, struct stat *);
58static char *ttyname_threaded(int fd);
59static char *ttyname_unthreaded(int fd);
60
61static pthread_mutex_t	ttyname_lock = PTHREAD_MUTEX_INITIALIZER;
62static pthread_key_t	ttyname_key;
63static int		ttyname_init = 0;
64
65char *
66ttyname(int fd)
67{
68	char           *ret;
69
70	if (__isthreaded == 0)
71		ret = ttyname_unthreaded(fd);
72	else
73		ret = ttyname_threaded(fd);
74	return (ret);
75}
76
77char *
78ttyname_r(int fd, char *buf, size_t len)
79{
80	struct dirent	*dirp;
81	DIR		*dp;
82	struct stat	dsb;
83	struct stat	sb;
84	char		*rval;
85	int		minlen;
86
87	rval = NULL;
88
89	/* Must be a terminal. */
90	if (!isatty(fd))
91		return (rval);
92	/* Must be a character device. */
93	if (_fstat(fd, &sb) || !S_ISCHR(sb.st_mode))
94		return (rval);
95	/* Must have enough room */
96	if (len <= sizeof(_PATH_DEV))
97		return (rval);
98
99	if ((dp = opendir(_PATH_DEV)) != NULL) {
100		memcpy(buf, _PATH_DEV, sizeof(_PATH_DEV));
101		for (rval = NULL; (dirp = readdir(dp)) != NULL;) {
102			if (dirp->d_fileno != sb.st_ino)
103				continue;
104			minlen = (len - (sizeof(_PATH_DEV) - 1)) < (dirp->d_namlen + 1) ?
105				(len - (sizeof(_PATH_DEV) - 1)) : (dirp->d_namlen + 1);
106			memcpy(buf + sizeof(_PATH_DEV) - 1, dirp->d_name, minlen);
107			if (stat(buf, &dsb) || sb.st_dev != dsb.st_dev ||
108			    sb.st_ino != dsb.st_ino)
109				continue;
110			rval = buf;
111			break;
112		}
113		(void) closedir(dp);
114	}
115	return (rval);
116}
117
118static char *
119ttyname_threaded(int fd)
120{
121	char	*buf;
122
123	if (ttyname_init == 0) {
124		_pthread_mutex_lock(&ttyname_lock);
125		if (ttyname_init == 0) {
126			if (_pthread_key_create(&ttyname_key, free)) {
127				_pthread_mutex_unlock(&ttyname_lock);
128				return (NULL);
129			}
130			ttyname_init = 1;
131		}
132		_pthread_mutex_unlock(&ttyname_lock);
133	}
134
135	/* Must have thread specific data field to put data */
136	if ((buf = _pthread_getspecific(ttyname_key)) == NULL) {
137		if ((buf = malloc(sizeof(_PATH_DEV) + MAXNAMLEN)) != NULL) {
138			if (_pthread_setspecific(ttyname_key, buf) != 0) {
139				free(buf);
140				return (NULL);
141			}
142		} else {
143			return (NULL);
144		}
145	}
146	return (ttyname_r(fd, buf, sizeof(_PATH_DEV) + MAXNAMLEN));
147}
148
149static char *
150ttyname_unthreaded(int fd)
151{
152	struct stat	sb;
153	struct termios	ttyb;
154	DB		*db;
155	DBT		data, key;
156	struct {
157		mode_t type;
158		dev_t dev;
159	} bkey;
160
161	/* Must be a terminal. */
162	if (tcgetattr(fd, &ttyb) < 0)
163		return (NULL);
164	/* Must be a character device. */
165	if (_fstat(fd, &sb) || !S_ISCHR(sb.st_mode))
166		return (NULL);
167
168	if ( (db = dbopen(_PATH_DEVDB, O_RDONLY, 0, DB_HASH, NULL)) ) {
169		memset(&bkey, 0, sizeof(bkey));
170		bkey.type = S_IFCHR;
171		bkey.dev = sb.st_rdev;
172		key.data = &bkey;
173		key.size = sizeof(bkey);
174		if (!(db->get)(db, &key, &data, 0)) {
175			bcopy(data.data,
176			    buf + sizeof(_PATH_DEV) - 1, data.size);
177			(void)(db->close)(db);
178			return (buf);
179		}
180		(void)(db->close)(db);
181	}
182	return (oldttyname(fd, &sb));
183}
184
185static char *
186oldttyname(int fd, struct stat *sb)
187{
188	struct dirent	*dirp;
189	struct stat	dsb;
190	DIR 		*dp;
191
192	if ((dp = opendir(_PATH_DEV)) == NULL)
193		return (NULL);
194
195	while ( (dirp = readdir(dp)) ) {
196		if (dirp->d_fileno != sb->st_ino)
197			continue;
198		bcopy(dirp->d_name, buf + sizeof(_PATH_DEV) - 1,
199		    dirp->d_namlen + 1);
200		if (stat(buf, &dsb) || sb->st_dev != dsb.st_dev ||
201		    sb->st_ino != dsb.st_ino)
202			continue;
203		(void)closedir(dp);
204		return (buf);
205	}
206	(void)closedir(dp);
207	return (NULL);
208}
209