xref: /onnv-gate/usr/src/lib/libc/port/gen/ttyname.c (revision 7688:2757e6e1bb2a)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
53646Sraf  * Common Development and Distribution License (the "License").
63646Sraf  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
213646Sraf 
220Sstevel@tonic-gate /*
236812Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
280Sstevel@tonic-gate /*	  All Rights Reserved  	*/
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * ttyname(f): return "/dev/X" (where X is a relative pathname
320Sstevel@tonic-gate  * under /dev/), which is the name of the tty character special
330Sstevel@tonic-gate  * file associated with the file descriptor f, or NULL if the
340Sstevel@tonic-gate  * pathname cannot be found.
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * Ttyname tries to find the tty file by matching major/minor
370Sstevel@tonic-gate  * device, file system ID, and inode numbers of the file
380Sstevel@tonic-gate  * descriptor parameter to those of files in the /dev/ directory.
390Sstevel@tonic-gate  *
400Sstevel@tonic-gate  * It attempts to find a match on major/minor device numbers,
410Sstevel@tonic-gate  * file system ID, and inode numbers, but failing to match on
420Sstevel@tonic-gate  * all three, settles for just a match on device numbers and
430Sstevel@tonic-gate  * file system ID.
440Sstevel@tonic-gate  *
450Sstevel@tonic-gate  * To achieve higher performance and more flexible functionality,
460Sstevel@tonic-gate  * ttyname first looks for the tty file in the directories specified
470Sstevel@tonic-gate  * in the configuration file /etc/ttysrch. Entries in /etc/ttysrch
480Sstevel@tonic-gate  * may be qualified to specify that a partial match may be acceptable.
490Sstevel@tonic-gate  * This further improves performance by allowing an entry which
500Sstevel@tonic-gate  * matches major/minor and file system ID, but not inode number
510Sstevel@tonic-gate  * without searching the entire /dev tree. If /etc/ttysrch does not
520Sstevel@tonic-gate  * exist, ttyname looks in a default list of directories.  If after
530Sstevel@tonic-gate  * looking in the most likely places, ttyname still cannot find the
540Sstevel@tonic-gate  * tty file, it recursively searches thru the rest of the /dev/
550Sstevel@tonic-gate  * directory.
560Sstevel@tonic-gate  *
570Sstevel@tonic-gate  * In addition to the public interfaces, ttyname() & ttyname_r(), which
580Sstevel@tonic-gate  * do the lookup based on an open file descriptor,
590Sstevel@tonic-gate  * the private interface _ttyname_dev() does the lookup based on a
600Sstevel@tonic-gate  * major/minor device.  It follows the same order of lookup rules and
610Sstevel@tonic-gate  * returns similar information, but matches on just the major/minor
620Sstevel@tonic-gate  * device numbers.
630Sstevel@tonic-gate  */
640Sstevel@tonic-gate 
656812Sraf #pragma weak _ttyname = ttyname
660Sstevel@tonic-gate 
676812Sraf #include "lint.h"
680Sstevel@tonic-gate #include "mtlib.h"
690Sstevel@tonic-gate #include "libc.h"
700Sstevel@tonic-gate #include "_libc_gettext.h"
710Sstevel@tonic-gate #include <sys/sysmacros.h>
720Sstevel@tonic-gate #include <sys/types.h>
730Sstevel@tonic-gate #include <dirent.h>
740Sstevel@tonic-gate #include <fcntl.h>
750Sstevel@tonic-gate #include <sys/stat.h>
760Sstevel@tonic-gate #include <stdlib.h>
770Sstevel@tonic-gate #include <ctype.h>
780Sstevel@tonic-gate #include <string.h>
790Sstevel@tonic-gate #include <stdio.h>
800Sstevel@tonic-gate #include <unistd.h>
810Sstevel@tonic-gate #include <thread.h>
820Sstevel@tonic-gate #include <synch.h>
830Sstevel@tonic-gate #include <errno.h>
840Sstevel@tonic-gate #include <limits.h>
850Sstevel@tonic-gate #include <sys/mkdev.h>
860Sstevel@tonic-gate #include "tsd.h"
870Sstevel@tonic-gate 
880Sstevel@tonic-gate typedef struct entry {
890Sstevel@tonic-gate 	char *name;
900Sstevel@tonic-gate 	int flags;
910Sstevel@tonic-gate } entry_t;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate typedef struct special {
940Sstevel@tonic-gate 	const char *spcl_name;	/* device name */
950Sstevel@tonic-gate 	dev_t spcl_rdev;	/* matching major/minor devnum */
960Sstevel@tonic-gate 	dev_t spcl_fsdev;	/* devnum of containing FS */
970Sstevel@tonic-gate 	ino_t spcl_inum;	/* inum of entry in FS */
980Sstevel@tonic-gate } spcl_t;
990Sstevel@tonic-gate 
1000Sstevel@tonic-gate static int srch_dir(const entry_t path, int match_mask, int depth,
1010Sstevel@tonic-gate     const entry_t skip_dirs[], struct stat64 *fsb);
1020Sstevel@tonic-gate static const entry_t *get_pri_dirs(void);
1030Sstevel@tonic-gate static char *ispts(struct stat64 *fsb, int match_mask);
1040Sstevel@tonic-gate static char *ispty(struct stat64 *fsb, int match_mask);
1050Sstevel@tonic-gate static void itoa(int i, char *ptr);
1060Sstevel@tonic-gate static char *_ttyname_common(struct stat64 *fsp, char *buffer,
1070Sstevel@tonic-gate     uint_t match_mask);
1080Sstevel@tonic-gate 
1090Sstevel@tonic-gate 
1100Sstevel@tonic-gate #define	MAX_DEV_PATH	TTYNAME_MAX
1110Sstevel@tonic-gate #define	MAX_SRCH_DEPTH	4
1120Sstevel@tonic-gate 
1130Sstevel@tonic-gate #define	MATCH_MM	1
1140Sstevel@tonic-gate #define	MATCH_FS	2
1150Sstevel@tonic-gate #define	MATCH_INO	4
1160Sstevel@tonic-gate #define	MATCH_ALL	7
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate #define	DEV		"/dev"
1190Sstevel@tonic-gate #define	TTYSRCH		"/etc/ttysrch"
1200Sstevel@tonic-gate #define	PTS		"/dev/pts"
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate static const entry_t dev_dir =
1230Sstevel@tonic-gate 	{ "/dev", MATCH_ALL };
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate static const entry_t def_srch_dirs[] = {	/* default search list */
1260Sstevel@tonic-gate 	{ "/dev/pts", MATCH_ALL },
127*7688SAaron.Zang@Sun.COM 	{ "/dev/vt", MATCH_ALL },
1280Sstevel@tonic-gate 	{ "/dev/term", MATCH_ALL },
1290Sstevel@tonic-gate 	{ "/dev/zcons", MATCH_ALL },
1300Sstevel@tonic-gate 	{ NULL, 0 }
1310Sstevel@tonic-gate };
1320Sstevel@tonic-gate 
1330Sstevel@tonic-gate static char *dir_buf;		/* directory buffer for ttysrch body */
1340Sstevel@tonic-gate static entry_t *dir_vec;	/* directory vector for ttysrch ptrs */
1350Sstevel@tonic-gate static size_t dir_size;		/* ttysrch file size */
1360Sstevel@tonic-gate static timestruc_t dir_mtim;	/* ttysrch file modification time */
1370Sstevel@tonic-gate static char rbuf[MAX_DEV_PATH]; /* perfect match file name */
1380Sstevel@tonic-gate static char dev_rbuf[MAX_DEV_PATH]; /* partial match file name */
1390Sstevel@tonic-gate static int dev_flag;		/* if set, dev + rdev match was found */
1400Sstevel@tonic-gate static spcl_t special_case[] = {
1410Sstevel@tonic-gate 	"/dev/tty", 0, 0, 0,
1420Sstevel@tonic-gate 	"/dev/console", 0, 0, 0,
1430Sstevel@tonic-gate 	"/dev/conslog", 0, 0, 0,
1440Sstevel@tonic-gate 	"/dev/systty", 0, 0, 0,
1457536SRoger.Faulkner@Sun.COM 	"/dev/wscons", 0, 0, 0,
1467536SRoger.Faulkner@Sun.COM 	"/dev/msglog", 0, 0, 0,
1470Sstevel@tonic-gate };
1480Sstevel@tonic-gate #define	NUMSPECIAL	(sizeof (special_case) / sizeof (spcl_t))
1490Sstevel@tonic-gate static spcl_t ptmspecial = {
1500Sstevel@tonic-gate 	"/dev/ptmx", 0, 0, 0
1510Sstevel@tonic-gate };
1520Sstevel@tonic-gate static	dev_t	ptcdev = NODEV;
1530Sstevel@tonic-gate static	dev_t	ptsldev = NODEV;
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate char *
_ttyname_dev(dev_t rdev,char * buffer,size_t buflen)1560Sstevel@tonic-gate _ttyname_dev(dev_t rdev, char *buffer, size_t buflen)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	struct stat64 fsb;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	fsb.st_rdev = rdev;
1610Sstevel@tonic-gate 
1620Sstevel@tonic-gate 	if (buflen < MAX_DEV_PATH) {
1630Sstevel@tonic-gate 		errno = ERANGE;
1640Sstevel@tonic-gate 		return (NULL);
1650Sstevel@tonic-gate 	}
1660Sstevel@tonic-gate 
1670Sstevel@tonic-gate 	return (_ttyname_common(&fsb, buffer, MATCH_MM));
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate 
1700Sstevel@tonic-gate /*
1710Sstevel@tonic-gate  * POSIX.1c Draft-6 version of the function ttyname_r.
1720Sstevel@tonic-gate  * It was implemented by Solaris 2.3.
1730Sstevel@tonic-gate  */
1740Sstevel@tonic-gate char *
ttyname_r(int f,char * buffer,int buflen)1756812Sraf ttyname_r(int f, char *buffer, int buflen)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate 	struct stat64 fsb;	/* what we are searching for */
1780Sstevel@tonic-gate 	/*
1790Sstevel@tonic-gate 	 * do we need to search anything at all? (is fildes a char special tty
1800Sstevel@tonic-gate 	 * file?)
1810Sstevel@tonic-gate 	 */
1820Sstevel@tonic-gate 	if (fstat64(f, &fsb) < 0) {
1830Sstevel@tonic-gate 		errno = EBADF;
1840Sstevel@tonic-gate 		return (0);
1850Sstevel@tonic-gate 	}
1860Sstevel@tonic-gate 	if ((isatty(f) == 0) ||
1870Sstevel@tonic-gate 	    ((fsb.st_mode & S_IFMT) != S_IFCHR)) {
1880Sstevel@tonic-gate 		errno = ENOTTY;
1890Sstevel@tonic-gate 		return (0);
1900Sstevel@tonic-gate 	}
1910Sstevel@tonic-gate 
1920Sstevel@tonic-gate 	if (buflen < MAX_DEV_PATH) {
1930Sstevel@tonic-gate 		errno = ERANGE;
1940Sstevel@tonic-gate 		return (0);
1950Sstevel@tonic-gate 	}
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate 	return (_ttyname_common(&fsb, buffer, MATCH_ALL));
1980Sstevel@tonic-gate }
1990Sstevel@tonic-gate 
2000Sstevel@tonic-gate static char *
_ttyname_common(struct stat64 * fsp,char * buffer,uint_t match_mask)2010Sstevel@tonic-gate _ttyname_common(struct stat64 *fsp, char *buffer, uint_t match_mask)
2020Sstevel@tonic-gate {
2030Sstevel@tonic-gate 	struct stat64 tfsb;
2040Sstevel@tonic-gate 	const entry_t *srch_dirs;	/* priority directories */
2050Sstevel@tonic-gate 	spcl_t *spclp;
2060Sstevel@tonic-gate 	int i;
2070Sstevel@tonic-gate 	int found = 0;
2080Sstevel@tonic-gate 	int dirno = 0;
2090Sstevel@tonic-gate 	int is_pts = 0;
2100Sstevel@tonic-gate 	char *retval = NULL;
2110Sstevel@tonic-gate 	char *pt = NULL;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 	/*
2140Sstevel@tonic-gate 	 * We can't use lmutex_lock() here because we call malloc()/free()
2155002Sraf 	 * and _libc_gettext().  Use the brute-force callout_lock_enter().
2160Sstevel@tonic-gate 	 */
2175002Sraf 	callout_lock_enter();
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/*
2200Sstevel@tonic-gate 	 * match special cases
2210Sstevel@tonic-gate 	 */
2220Sstevel@tonic-gate 
2230Sstevel@tonic-gate 	for (spclp = special_case, i = 0; i < NUMSPECIAL; spclp++, i++) {
2240Sstevel@tonic-gate 		if ((spclp->spcl_inum | spclp->spcl_fsdev |
2250Sstevel@tonic-gate 		    spclp->spcl_rdev) == 0) {
2260Sstevel@tonic-gate 			if (stat64(spclp->spcl_name, &tfsb) != 0)
2270Sstevel@tonic-gate 				continue;
2280Sstevel@tonic-gate 			spclp->spcl_rdev = tfsb.st_rdev;
2290Sstevel@tonic-gate 			spclp->spcl_fsdev = tfsb.st_dev;
2300Sstevel@tonic-gate 			spclp->spcl_inum = tfsb.st_ino;
2310Sstevel@tonic-gate 		}
2320Sstevel@tonic-gate 		if (match_mask == MATCH_MM) {
2330Sstevel@tonic-gate 			if (spclp->spcl_rdev == fsp->st_rdev) {
2340Sstevel@tonic-gate 				retval = strcpy(rbuf, spclp->spcl_name);
2350Sstevel@tonic-gate 				goto out;
2360Sstevel@tonic-gate 			}
2370Sstevel@tonic-gate 		} else if (spclp->spcl_fsdev == fsp->st_dev &&
2380Sstevel@tonic-gate 		    spclp->spcl_rdev == fsp->st_rdev &&
2390Sstevel@tonic-gate 		    spclp->spcl_inum == fsp->st_ino) {
2400Sstevel@tonic-gate 			retval = strcpy(rbuf, spclp->spcl_name);
2410Sstevel@tonic-gate 			goto out;
2420Sstevel@tonic-gate 		}
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 	/*
2450Sstevel@tonic-gate 	 * additional special case: ptm clone device
2460Sstevel@tonic-gate 	 *   ptm devs have no entries in /dev
2470Sstevel@tonic-gate 	 *   if major number matches, just short circuit any further lookup
2480Sstevel@tonic-gate 	 *   NOTE: the minor number of /dev/ptmx is the ptm major number
2490Sstevel@tonic-gate 	 */
2500Sstevel@tonic-gate 	spclp = &ptmspecial;
2510Sstevel@tonic-gate 	if ((spclp->spcl_inum | spclp->spcl_fsdev | spclp->spcl_rdev) == 0) {
2520Sstevel@tonic-gate 		if (stat64(spclp->spcl_name, &tfsb) == 0) {
2530Sstevel@tonic-gate 			spclp->spcl_rdev = tfsb.st_rdev;
2540Sstevel@tonic-gate 			spclp->spcl_fsdev = tfsb.st_dev;
2550Sstevel@tonic-gate 			spclp->spcl_inum = tfsb.st_ino;
2560Sstevel@tonic-gate 		}
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 	if ((spclp->spcl_rdev != 0) &&
2590Sstevel@tonic-gate 	    (minor(spclp->spcl_rdev) == major(fsp->st_rdev)))
2600Sstevel@tonic-gate 		goto out;
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	/*
2630Sstevel@tonic-gate 	 * additional special case: pty dev
2640Sstevel@tonic-gate 	 *  one of the known default pairs of /dev/ptyXX or /dev/ttyXX
2650Sstevel@tonic-gate 	 */
2660Sstevel@tonic-gate 	if ((retval = ispty(fsp, match_mask)) != NULL)
2670Sstevel@tonic-gate 		goto out;
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	/*
2700Sstevel@tonic-gate 	 * search the priority directories
2710Sstevel@tonic-gate 	 */
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 
2740Sstevel@tonic-gate 	srch_dirs = get_pri_dirs();
2750Sstevel@tonic-gate 	dev_flag = 0;
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	while ((!found) && (srch_dirs[dirno].name != NULL)) {
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate 		/*
2800Sstevel@tonic-gate 		 * if /dev is one of the priority directories, only
2810Sstevel@tonic-gate 		 * search its top level(set depth = MAX_SEARCH_DEPTH)
2820Sstevel@tonic-gate 		 */
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 		/*
2850Sstevel@tonic-gate 		 * Is /dev/pts then just do a quick check. We don't have
2860Sstevel@tonic-gate 		 * to stat the entire /dev/pts dir.
2870Sstevel@tonic-gate 		 */
2880Sstevel@tonic-gate 		if (strcmp(PTS, srch_dirs[dirno].name) == NULL) {
2890Sstevel@tonic-gate 			if ((pt = ispts(fsp, match_mask)) != NULL) {
2900Sstevel@tonic-gate 				is_pts = 1;
2910Sstevel@tonic-gate 				found = 1;
2920Sstevel@tonic-gate 			}
2930Sstevel@tonic-gate 		} else {
2940Sstevel@tonic-gate 			found = srch_dir(srch_dirs[dirno], match_mask,
2954443Slt200341 			    ((strcmp(srch_dirs[dirno].name, dev_dir.name)
2964443Slt200341 			    == 0) ? MAX_SRCH_DEPTH : 1), 0, fsp);
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 		dirno++;
2990Sstevel@tonic-gate 	}
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	/*
3020Sstevel@tonic-gate 	 * search the /dev/ directory, skipping priority directories
3030Sstevel@tonic-gate 	 */
3040Sstevel@tonic-gate 	if (!found)
3050Sstevel@tonic-gate 		found = srch_dir(dev_dir, match_mask, 0, srch_dirs, fsp);
3060Sstevel@tonic-gate 
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 	/*
3090Sstevel@tonic-gate 	 * return
3100Sstevel@tonic-gate 	 */
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	if (found) {
3130Sstevel@tonic-gate 		if (is_pts)
3140Sstevel@tonic-gate 			retval = pt;
3150Sstevel@tonic-gate 		else
3160Sstevel@tonic-gate 			retval = rbuf;
3170Sstevel@tonic-gate 	} else if (dev_flag)
3180Sstevel@tonic-gate 		retval = dev_rbuf;
3190Sstevel@tonic-gate 	else
3200Sstevel@tonic-gate 		retval = NULL;
3210Sstevel@tonic-gate out:	retval = (retval ? strcpy(buffer, retval) : NULL);
3225002Sraf 	callout_lock_exit();
3230Sstevel@tonic-gate 	return (retval);
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate /*
3270Sstevel@tonic-gate  * POSIX.1c standard version of the function ttyname_r.
3280Sstevel@tonic-gate  * User gets it via static ttyname_r from the header file.
3290Sstevel@tonic-gate  */
3300Sstevel@tonic-gate int
__posix_ttyname_r(int fildes,char * name,size_t namesize)3310Sstevel@tonic-gate __posix_ttyname_r(int fildes, char *name, size_t namesize)
3320Sstevel@tonic-gate {
3330Sstevel@tonic-gate 	int nerrno = 0;
3340Sstevel@tonic-gate 	int oerrno = errno;
3350Sstevel@tonic-gate 	int namelen;
3360Sstevel@tonic-gate 
3370Sstevel@tonic-gate 	errno = 0;
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 	if (namesize > INT_MAX)
3400Sstevel@tonic-gate 		namelen = INT_MAX;
3410Sstevel@tonic-gate 	else
3420Sstevel@tonic-gate 		namelen = (int)namesize;
3430Sstevel@tonic-gate 
3446812Sraf 	if (ttyname_r(fildes, name, namelen) == NULL) {
3450Sstevel@tonic-gate 		if (errno == 0)
3460Sstevel@tonic-gate 			nerrno = EINVAL;
3470Sstevel@tonic-gate 		else
3480Sstevel@tonic-gate 			nerrno = errno;
3490Sstevel@tonic-gate 	}
3500Sstevel@tonic-gate 	errno = oerrno;
3510Sstevel@tonic-gate 	return (nerrno);
3520Sstevel@tonic-gate }
3530Sstevel@tonic-gate 
3540Sstevel@tonic-gate /*
3550Sstevel@tonic-gate  * Checks if the name is under /dev/pts directory
3560Sstevel@tonic-gate  */
3570Sstevel@tonic-gate static char *
ispts(struct stat64 * fsb,int match_mask)3580Sstevel@tonic-gate ispts(struct stat64 *fsb, int match_mask)
3590Sstevel@tonic-gate {
3600Sstevel@tonic-gate 	static  char	buf[MAX_DEV_PATH];
3610Sstevel@tonic-gate 	struct	stat64	stb;
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	(void) strcpy(buf, "/dev/pts/");
3640Sstevel@tonic-gate 	itoa(minor(fsb->st_rdev), buf+strlen(buf));
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 	if (stat64(buf, &stb) != 0)
3670Sstevel@tonic-gate 		return (NULL);
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	if (match_mask == MATCH_MM) {
3700Sstevel@tonic-gate 		if (stb.st_rdev == fsb->st_rdev)
3710Sstevel@tonic-gate 			return (buf);
3724443Slt200341 	} else if (stb.st_rdev == fsb->st_rdev && stb.st_dev == fsb->st_dev &&
3734443Slt200341 	    stb.st_ino == fsb->st_ino)
3740Sstevel@tonic-gate 			return (buf);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	return (NULL);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /*
3800Sstevel@tonic-gate  * Checks if the dev is a known pty master or slave device
3810Sstevel@tonic-gate  */
3820Sstevel@tonic-gate #define	MAXDEFAULTPTY	48
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate static char *
ispty(struct stat64 * fsb,int match_mask)3850Sstevel@tonic-gate ispty(struct stat64 *fsb, int match_mask)
3860Sstevel@tonic-gate {
3870Sstevel@tonic-gate 	static char	buf[16];	/* big enough for "/dev/XtyXX" */
3880Sstevel@tonic-gate 	struct	stat64	stb;
3890Sstevel@tonic-gate 	minor_t dmin;
3900Sstevel@tonic-gate 	char prefix;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	if (ptsldev == NODEV && stat64("/dev/ttyp0", &stb) == 0)
3930Sstevel@tonic-gate 		ptsldev = stb.st_rdev;
3940Sstevel@tonic-gate 
3950Sstevel@tonic-gate 	/*
3960Sstevel@tonic-gate 	 * check for a ptsl dev (/dev/ttyXX)
3970Sstevel@tonic-gate 	 */
3980Sstevel@tonic-gate 	prefix = 't';
3990Sstevel@tonic-gate 	if (major(fsb->st_rdev) != major(ptsldev)) {
4000Sstevel@tonic-gate 		/*
4010Sstevel@tonic-gate 		 * not a ptsl, check for a ptc
4020Sstevel@tonic-gate 		 */
4030Sstevel@tonic-gate 		if (ptcdev == NODEV && stat64("/dev/ptyp0", &stb) == 0)
4040Sstevel@tonic-gate 			ptcdev = stb.st_rdev;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 		/*
4070Sstevel@tonic-gate 		 * check for a ptc dev (/dev/ptyXX)
4080Sstevel@tonic-gate 		 */
4090Sstevel@tonic-gate 		prefix = 'p';
4100Sstevel@tonic-gate 		if (major(fsb->st_rdev) != major(ptcdev))
4110Sstevel@tonic-gate 			return (NULL);
4120Sstevel@tonic-gate 	}
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/*
4150Sstevel@tonic-gate 	 * check if minor number is in the known range
4160Sstevel@tonic-gate 	 */
4170Sstevel@tonic-gate 	dmin = minor(fsb->st_rdev);
4180Sstevel@tonic-gate 	if (dmin > MAXDEFAULTPTY)
4190Sstevel@tonic-gate 		return (NULL);
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	/*
4220Sstevel@tonic-gate 	 * modify name based on minor number
4230Sstevel@tonic-gate 	 */
4240Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "/dev/%cty%c%c",
4250Sstevel@tonic-gate 	    prefix, 'p' + dmin / 16, "0123456789abcdef"[dmin % 16]);
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate 	if (stat64(buf, &stb) != 0)
4280Sstevel@tonic-gate 		return (NULL);
4290Sstevel@tonic-gate 
4300Sstevel@tonic-gate 	if (match_mask == MATCH_MM) {
4310Sstevel@tonic-gate 		if (stb.st_rdev == fsb->st_rdev)
4320Sstevel@tonic-gate 			return (buf);
4330Sstevel@tonic-gate 	} else if (stb.st_rdev == fsb->st_rdev &&
4344443Slt200341 	    stb.st_dev == fsb->st_dev &&
4354443Slt200341 	    stb.st_ino == fsb->st_ino)
4360Sstevel@tonic-gate 			return (buf);
4370Sstevel@tonic-gate 
4380Sstevel@tonic-gate 	return (NULL);
4390Sstevel@tonic-gate }
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 
4420Sstevel@tonic-gate /*
4430Sstevel@tonic-gate  * Converts a number to a string (null terminated).
4440Sstevel@tonic-gate  */
4450Sstevel@tonic-gate static void
itoa(int i,char * ptr)4460Sstevel@tonic-gate itoa(int i, char *ptr)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	int dig = 0;
4490Sstevel@tonic-gate 	int tempi;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	tempi = i;
4520Sstevel@tonic-gate 	do {
4530Sstevel@tonic-gate 		dig++;
4540Sstevel@tonic-gate 		tempi /= 10;
4550Sstevel@tonic-gate 	} while (tempi);
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate 	ptr += dig;
4580Sstevel@tonic-gate 	*ptr = '\0';
4590Sstevel@tonic-gate 	while (--dig >= 0) {
4600Sstevel@tonic-gate 		*(--ptr) = i % 10 + '0';
4610Sstevel@tonic-gate 		i /= 10;
4620Sstevel@tonic-gate 	}
4630Sstevel@tonic-gate }
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate /*
4660Sstevel@tonic-gate  * srch_dir() searches directory path and all directories under it up
4670Sstevel@tonic-gate  * to depth directories deep for a file described by a stat structure
4680Sstevel@tonic-gate  * fsb.  It puts the answer into rbuf.  If a match is found on device
4690Sstevel@tonic-gate  * number only, the file name is put into dev_rbuf and dev_flag is set.
4700Sstevel@tonic-gate  *
4710Sstevel@tonic-gate  * srch_dir() returns 1 if a match (on device and inode) is found,
4720Sstevel@tonic-gate  * or 0 otherwise.
4730Sstevel@tonic-gate  *
4740Sstevel@tonic-gate  */
4750Sstevel@tonic-gate 
4760Sstevel@tonic-gate static int
srch_dir(const entry_t path,int match_mask,int depth,const entry_t skip_dirs[],struct stat64 * fsb)4770Sstevel@tonic-gate srch_dir(const entry_t path,	/* current path */
4780Sstevel@tonic-gate 	int match_mask,		/* flags mask */
4790Sstevel@tonic-gate 	int depth,		/* current depth (/dev = 0) */
4800Sstevel@tonic-gate 	const entry_t skip_dirs[], /* directories not needing searching */
4810Sstevel@tonic-gate 	struct stat64 *fsb)	/* the file being searched for */
4820Sstevel@tonic-gate {
4830Sstevel@tonic-gate 	DIR *dirp;
4840Sstevel@tonic-gate 	struct dirent64 *direntp;
4850Sstevel@tonic-gate 	struct stat64 tsb;
4860Sstevel@tonic-gate 	char file_name[MAX_DEV_PATH];
4870Sstevel@tonic-gate 	entry_t file;
4880Sstevel@tonic-gate 	char *last_comp;
4890Sstevel@tonic-gate 	int found = 0;
4900Sstevel@tonic-gate 	int dirno = 0;
4910Sstevel@tonic-gate 	size_t path_len;
4920Sstevel@tonic-gate 
4930Sstevel@tonic-gate 	file.name = file_name;
4940Sstevel@tonic-gate 	file.flags = path.flags & match_mask;
4950Sstevel@tonic-gate 	if (file.flags == 0)
4960Sstevel@tonic-gate 		file.flags = match_mask;
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	/*
4990Sstevel@tonic-gate 	 * do we need to search this directory? (always search /dev at depth 0)
5000Sstevel@tonic-gate 	 */
5010Sstevel@tonic-gate 	if ((skip_dirs != NULL) && (depth != 0))
5020Sstevel@tonic-gate 		while (skip_dirs[dirno].name != NULL)
5030Sstevel@tonic-gate 			if (strcmp(skip_dirs[dirno++].name, path.name) == 0)
5040Sstevel@tonic-gate 				return (0);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	/*
5070Sstevel@tonic-gate 	 * open directory
5080Sstevel@tonic-gate 	 */
5090Sstevel@tonic-gate 	if ((dirp = opendir(path.name)) == NULL) {
5100Sstevel@tonic-gate 		return (0);
5110Sstevel@tonic-gate 	}
5120Sstevel@tonic-gate 
5130Sstevel@tonic-gate 	path_len = strlen(path.name);
5140Sstevel@tonic-gate 	(void) strcpy(file_name, path.name);
5150Sstevel@tonic-gate 	last_comp = file_name + path_len;
5160Sstevel@tonic-gate 	*last_comp++ = '/';
5170Sstevel@tonic-gate 
5180Sstevel@tonic-gate 	/*
5190Sstevel@tonic-gate 	 * read thru the directory
5200Sstevel@tonic-gate 	 */
5210Sstevel@tonic-gate 	while ((!found) && ((direntp = readdir64(dirp)) != NULL)) {
5223646Sraf 		/*
5233646Sraf 		 * skip "." and ".." entries, if present
5243646Sraf 		 */
5253646Sraf 		if (direntp->d_name[0] == '.' &&
5263646Sraf 		    (strcmp(direntp->d_name, ".") == 0 ||
5273646Sraf 		    strcmp(direntp->d_name, "..") == 0))
5283646Sraf 			continue;
5290Sstevel@tonic-gate 
5300Sstevel@tonic-gate 		/*
5310Sstevel@tonic-gate 		 * if the file name (path + "/" + d_name + NULL) would be too
5320Sstevel@tonic-gate 		 * long, skip it
5330Sstevel@tonic-gate 		 */
5340Sstevel@tonic-gate 		if ((path_len + strlen(direntp->d_name) + 2) > MAX_DEV_PATH)
5350Sstevel@tonic-gate 			continue;
5360Sstevel@tonic-gate 
5373646Sraf 		(void) strcpy(last_comp, direntp->d_name);
5380Sstevel@tonic-gate 		if (stat64(file_name, &tsb) < 0)
5390Sstevel@tonic-gate 			continue;
5400Sstevel@tonic-gate 
541*7688SAaron.Zang@Sun.COM 		if (strcmp(file_name, "/dev/vt/active") == 0)
542*7688SAaron.Zang@Sun.COM 			continue;
543*7688SAaron.Zang@Sun.COM 
5440Sstevel@tonic-gate 		/*
5454443Slt200341 		 * skip "/dev/syscon" because it may be an invalid link after
5464443Slt200341 		 * single user mode.
5474443Slt200341 		 */
5484443Slt200341 		if (strcmp(file_name, "/dev/syscon") == 0)
5494443Slt200341 			continue;
5504443Slt200341 
5514443Slt200341 		/*
5520Sstevel@tonic-gate 		 * if a file is a directory and we are not too deep, recurse
5530Sstevel@tonic-gate 		 */
5540Sstevel@tonic-gate 		if ((tsb.st_mode & S_IFMT) == S_IFDIR)
5550Sstevel@tonic-gate 			if (depth < MAX_SRCH_DEPTH)
5560Sstevel@tonic-gate 				found = srch_dir(file, match_mask, depth+1,
5574443Slt200341 				    skip_dirs, fsb);
5580Sstevel@tonic-gate 			else
5590Sstevel@tonic-gate 				continue;
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 		/*
5620Sstevel@tonic-gate 		 * else if it is not a directory, is it a character special
5630Sstevel@tonic-gate 		 * file?
5640Sstevel@tonic-gate 		 */
5650Sstevel@tonic-gate 		else if ((tsb.st_mode & S_IFMT) == S_IFCHR) {
5660Sstevel@tonic-gate 			int flag = 0;
5670Sstevel@tonic-gate 			if (tsb.st_dev == fsb->st_dev)
5680Sstevel@tonic-gate 				flag |= MATCH_FS;
5690Sstevel@tonic-gate 			if (tsb.st_rdev == fsb->st_rdev)
5700Sstevel@tonic-gate 				flag |= MATCH_MM;
5710Sstevel@tonic-gate 			if (tsb.st_ino == fsb->st_ino)
5720Sstevel@tonic-gate 				flag |= MATCH_INO;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 			if ((flag & file.flags) == file.flags) {
5750Sstevel@tonic-gate 				(void) strcpy(rbuf, file.name);
5760Sstevel@tonic-gate 				found = 1;
5770Sstevel@tonic-gate 			} else if ((flag & (MATCH_MM | MATCH_FS)) ==
5784443Slt200341 			    (MATCH_MM | MATCH_FS)) {
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 				/*
5810Sstevel@tonic-gate 				 * no (inodes do not match), but save the name
5820Sstevel@tonic-gate 				 * for later
5830Sstevel@tonic-gate 				 */
5840Sstevel@tonic-gate 				(void) strcpy(dev_rbuf, file.name);
5850Sstevel@tonic-gate 				dev_flag = 1;
5860Sstevel@tonic-gate 			}
5870Sstevel@tonic-gate 		}
5880Sstevel@tonic-gate 	}
5890Sstevel@tonic-gate 	(void) closedir(dirp);
5900Sstevel@tonic-gate 	return (found);
5910Sstevel@tonic-gate }
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate /*
5950Sstevel@tonic-gate  * get_pri_dirs() - returns a pointer to an array of strings, where each string
5960Sstevel@tonic-gate  * is a priority directory name.  The end of the array is marked by a NULL
5970Sstevel@tonic-gate  * pointer.  The priority directories' names are obtained from the file
5980Sstevel@tonic-gate  * /etc/ttysrch if it exists and is readable, or if not, a default hard-coded
5990Sstevel@tonic-gate  * list of directories.
6000Sstevel@tonic-gate  *
6010Sstevel@tonic-gate  * /etc/ttysrch, if used, is read in as a string of characters into memory and
6020Sstevel@tonic-gate  * then parsed into strings of priority directory names, omitting comments and
6030Sstevel@tonic-gate  * blank lines.
6040Sstevel@tonic-gate  *
6050Sstevel@tonic-gate  */
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate #define	START_STATE	1
6080Sstevel@tonic-gate #define	COMMENT_STATE	2
6090Sstevel@tonic-gate #define	DIRNAME_STATE	3
6100Sstevel@tonic-gate #define	FLAG_STATE	4
6110Sstevel@tonic-gate #define	CHECK_STATE	5
6120Sstevel@tonic-gate 
6130Sstevel@tonic-gate #define	COMMENT_CHAR	'#'
6140Sstevel@tonic-gate #define	EOLN_CHAR	'\n'
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate static const entry_t *
get_pri_dirs(void)6170Sstevel@tonic-gate get_pri_dirs(void)
6180Sstevel@tonic-gate {
6190Sstevel@tonic-gate 	int fd, state;
6200Sstevel@tonic-gate 	size_t sz;
6210Sstevel@tonic-gate 	ssize_t size;
6220Sstevel@tonic-gate 	struct stat64 sb;
6230Sstevel@tonic-gate 	char *buf, *ebuf;
6240Sstevel@tonic-gate 	entry_t *vec;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	/*
6270Sstevel@tonic-gate 	 * if no /etc/ttysrch, use defaults
6280Sstevel@tonic-gate 	 */
6290Sstevel@tonic-gate 	if ((fd = open(TTYSRCH, 0)) < 0)
6300Sstevel@tonic-gate 		return (def_srch_dirs);
6310Sstevel@tonic-gate 
6320Sstevel@tonic-gate 	if (fstat64(fd, &sb) < 0) {
6330Sstevel@tonic-gate 		(void) close(fd);
6340Sstevel@tonic-gate 		return (def_srch_dirs);
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	sz = (size_t)sb.st_size;
6380Sstevel@tonic-gate 	if (dir_vec != NULL && sz == dir_size &&
6390Sstevel@tonic-gate 	    sb.st_mtim.tv_sec == dir_mtim.tv_sec &&
6400Sstevel@tonic-gate 	    sb.st_mtim.tv_nsec == dir_mtim.tv_nsec) {
6410Sstevel@tonic-gate 		/*
6420Sstevel@tonic-gate 		 * size & modification time match
6430Sstevel@tonic-gate 		 * no need to reread TTYSRCH
6440Sstevel@tonic-gate 		 * just return old pointer
6450Sstevel@tonic-gate 		 */
6460Sstevel@tonic-gate 		(void) close(fd);
6470Sstevel@tonic-gate 		return (dir_vec);
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 	buf = realloc(dir_buf, sz + 1);
6500Sstevel@tonic-gate 	if (buf != NULL) {
6510Sstevel@tonic-gate 		dir_buf = buf;
6520Sstevel@tonic-gate 		size = read(fd, dir_buf, sz);
6530Sstevel@tonic-gate 	}
6540Sstevel@tonic-gate 	(void) close(fd);
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	if (buf == NULL || size < 0) {
6570Sstevel@tonic-gate 		if (dir_vec != NULL) {
6580Sstevel@tonic-gate 			free(dir_vec);
6590Sstevel@tonic-gate 			dir_vec = NULL;
6600Sstevel@tonic-gate 		}
6610Sstevel@tonic-gate 		return ((entry_t *)def_srch_dirs);
6620Sstevel@tonic-gate 	}
6630Sstevel@tonic-gate 	dir_size = sz;
6640Sstevel@tonic-gate 	dir_mtim = sb.st_mtim;
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	/*
6670Sstevel@tonic-gate 	 * ensure newline termination for buffer.  Add an extra
6680Sstevel@tonic-gate 	 * entry to dir_vec for null terminator
6690Sstevel@tonic-gate 	 */
6700Sstevel@tonic-gate 	ebuf = &dir_buf[size];
6710Sstevel@tonic-gate 	*ebuf++ = '\n';
6720Sstevel@tonic-gate 	for (sz = 1, buf = dir_buf; buf < ebuf; ++buf)
6730Sstevel@tonic-gate 		if (*buf == '\n')
6740Sstevel@tonic-gate 			++sz;
6750Sstevel@tonic-gate 
6760Sstevel@tonic-gate 	sz *= sizeof (*dir_vec);
6770Sstevel@tonic-gate 	vec = realloc(dir_vec, sz);
6780Sstevel@tonic-gate 	if (vec == NULL) {
6790Sstevel@tonic-gate 		if (dir_vec != NULL) {
6800Sstevel@tonic-gate 			free(dir_vec);
6810Sstevel@tonic-gate 			dir_vec = NULL;
6820Sstevel@tonic-gate 		}
6830Sstevel@tonic-gate 		return (def_srch_dirs);
6840Sstevel@tonic-gate 	}
6850Sstevel@tonic-gate 	dir_vec = vec;
6860Sstevel@tonic-gate 	state = START_STATE;
6870Sstevel@tonic-gate 	for (buf = dir_buf; buf < ebuf; ++buf) {
6880Sstevel@tonic-gate 		switch (state) {
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate 		case START_STATE:
6910Sstevel@tonic-gate 			if (*buf == COMMENT_CHAR) {
6920Sstevel@tonic-gate 				state = COMMENT_STATE;
6930Sstevel@tonic-gate 				break;
6940Sstevel@tonic-gate 			}
6950Sstevel@tonic-gate 			if (!isspace(*buf))	/* skip leading white space */
6960Sstevel@tonic-gate 				state = DIRNAME_STATE;
6970Sstevel@tonic-gate 				vec->name = buf;
6980Sstevel@tonic-gate 				vec->flags = 0;
6990Sstevel@tonic-gate 			break;
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 		case COMMENT_STATE:
7020Sstevel@tonic-gate 			if (*buf == EOLN_CHAR)
7030Sstevel@tonic-gate 				state = START_STATE;
7040Sstevel@tonic-gate 			break;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 		case DIRNAME_STATE:
7070Sstevel@tonic-gate 			if (*buf == EOLN_CHAR) {
7080Sstevel@tonic-gate 				state = CHECK_STATE;
7090Sstevel@tonic-gate 				*buf = '\0';
7100Sstevel@tonic-gate 			} else if (isspace(*buf)) {
7110Sstevel@tonic-gate 				/* skip trailing white space */
7120Sstevel@tonic-gate 				state = FLAG_STATE;
7130Sstevel@tonic-gate 				*buf = '\0';
7140Sstevel@tonic-gate 			}
7150Sstevel@tonic-gate 			break;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 		case FLAG_STATE:
7180Sstevel@tonic-gate 			switch (*buf) {
7190Sstevel@tonic-gate 				case 'M':
7200Sstevel@tonic-gate 					vec->flags |= MATCH_MM;
7210Sstevel@tonic-gate 					break;
7220Sstevel@tonic-gate 				case 'F':
7230Sstevel@tonic-gate 					vec->flags |= MATCH_FS;
7240Sstevel@tonic-gate 					break;
7250Sstevel@tonic-gate 				case 'I':
7260Sstevel@tonic-gate 					vec->flags |= MATCH_INO;
7270Sstevel@tonic-gate 					break;
7280Sstevel@tonic-gate 				case EOLN_CHAR:
7290Sstevel@tonic-gate 					state = CHECK_STATE;
7300Sstevel@tonic-gate 					break;
7310Sstevel@tonic-gate 			}
7320Sstevel@tonic-gate 			break;
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 		case CHECK_STATE:
7350Sstevel@tonic-gate 			if (strncmp(vec->name, DEV, strlen(DEV)) != 0) {
7360Sstevel@tonic-gate 				int tfd = open("/dev/console", O_WRONLY);
7370Sstevel@tonic-gate 				if (tfd >= 0) {
7380Sstevel@tonic-gate 					char buf[256];
7390Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
7404443Slt200341 					    _libc_gettext(
7414443Slt200341 "ERROR: Entry '%s' in /etc/ttysrch ignored.\n"), vec->name);
7420Sstevel@tonic-gate 					(void) write(tfd, buf, strlen(buf));
7430Sstevel@tonic-gate 					(void) close(tfd);
7440Sstevel@tonic-gate 				}
7450Sstevel@tonic-gate 			} else {
7460Sstevel@tonic-gate 				char *slash;
7470Sstevel@tonic-gate 				slash = vec->name + strlen(vec->name) - 1;
7480Sstevel@tonic-gate 				while (*slash == '/')
7490Sstevel@tonic-gate 					*slash-- = '\0';
7500Sstevel@tonic-gate 				if (vec->flags == 0)
7510Sstevel@tonic-gate 					vec->flags = MATCH_ALL;
7520Sstevel@tonic-gate 				vec++;
7530Sstevel@tonic-gate 			}
7540Sstevel@tonic-gate 			state = START_STATE;
7550Sstevel@tonic-gate 			/*
7560Sstevel@tonic-gate 			 * This state does not consume a character, so
7570Sstevel@tonic-gate 			 * reposition the pointer.
7580Sstevel@tonic-gate 			 */
7590Sstevel@tonic-gate 			buf--;
7600Sstevel@tonic-gate 			break;
7610Sstevel@tonic-gate 
7620Sstevel@tonic-gate 		}
7630Sstevel@tonic-gate 	}
7640Sstevel@tonic-gate 	vec->name = NULL;
7650Sstevel@tonic-gate 	return (dir_vec);
7660Sstevel@tonic-gate }
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 
7690Sstevel@tonic-gate char *
ttyname(int f)7700Sstevel@tonic-gate ttyname(int f)
7710Sstevel@tonic-gate {
7720Sstevel@tonic-gate 	char *ans = tsdalloc(_T_TTYNAME, MAX_DEV_PATH, NULL);
7730Sstevel@tonic-gate 
7740Sstevel@tonic-gate 	if (ans == NULL)
7750Sstevel@tonic-gate 		return (NULL);
7766812Sraf 	return (ttyname_r(f, ans, MAX_DEV_PATH));
7770Sstevel@tonic-gate }
778