xref: /illumos-gate/usr/src/lib/libc/port/gen/ttyname.c (revision 13b62818)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*13b62818Sraf  * Common Development and Distribution License (the "License").
6*13b62818Sraf  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21*13b62818Sraf 
227c478bd9Sstevel@tonic-gate /*
23*13b62818Sraf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
307c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
317c478bd9Sstevel@tonic-gate 
327c478bd9Sstevel@tonic-gate /*
337c478bd9Sstevel@tonic-gate  * ttyname(f): return "/dev/X" (where X is a relative pathname
347c478bd9Sstevel@tonic-gate  * under /dev/), which is the name of the tty character special
357c478bd9Sstevel@tonic-gate  * file associated with the file descriptor f, or NULL if the
367c478bd9Sstevel@tonic-gate  * pathname cannot be found.
377c478bd9Sstevel@tonic-gate  *
387c478bd9Sstevel@tonic-gate  * Ttyname tries to find the tty file by matching major/minor
397c478bd9Sstevel@tonic-gate  * device, file system ID, and inode numbers of the file
407c478bd9Sstevel@tonic-gate  * descriptor parameter to those of files in the /dev/ directory.
417c478bd9Sstevel@tonic-gate  *
427c478bd9Sstevel@tonic-gate  * It attempts to find a match on major/minor device numbers,
437c478bd9Sstevel@tonic-gate  * file system ID, and inode numbers, but failing to match on
447c478bd9Sstevel@tonic-gate  * all three, settles for just a match on device numbers and
457c478bd9Sstevel@tonic-gate  * file system ID.
467c478bd9Sstevel@tonic-gate  *
477c478bd9Sstevel@tonic-gate  * To achieve higher performance and more flexible functionality,
487c478bd9Sstevel@tonic-gate  * ttyname first looks for the tty file in the directories specified
497c478bd9Sstevel@tonic-gate  * in the configuration file /etc/ttysrch. Entries in /etc/ttysrch
507c478bd9Sstevel@tonic-gate  * may be qualified to specify that a partial match may be acceptable.
517c478bd9Sstevel@tonic-gate  * This further improves performance by allowing an entry which
527c478bd9Sstevel@tonic-gate  * matches major/minor and file system ID, but not inode number
537c478bd9Sstevel@tonic-gate  * without searching the entire /dev tree. If /etc/ttysrch does not
547c478bd9Sstevel@tonic-gate  * exist, ttyname looks in a default list of directories.  If after
557c478bd9Sstevel@tonic-gate  * looking in the most likely places, ttyname still cannot find the
567c478bd9Sstevel@tonic-gate  * tty file, it recursively searches thru the rest of the /dev/
577c478bd9Sstevel@tonic-gate  * directory.
587c478bd9Sstevel@tonic-gate  *
597c478bd9Sstevel@tonic-gate  * In addition to the public interfaces, ttyname() & ttyname_r(), which
607c478bd9Sstevel@tonic-gate  * do the lookup based on an open file descriptor,
617c478bd9Sstevel@tonic-gate  * the private interface _ttyname_dev() does the lookup based on a
627c478bd9Sstevel@tonic-gate  * major/minor device.  It follows the same order of lookup rules and
637c478bd9Sstevel@tonic-gate  * returns similar information, but matches on just the major/minor
647c478bd9Sstevel@tonic-gate  * device numbers.
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #pragma weak ttyname = _ttyname
687c478bd9Sstevel@tonic-gate #pragma weak ttyname_r = _ttyname_r
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate #include "synonyms.h"
717c478bd9Sstevel@tonic-gate #include "mtlib.h"
727c478bd9Sstevel@tonic-gate #include "libc.h"
737c478bd9Sstevel@tonic-gate #include "_libc_gettext.h"
747c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
757c478bd9Sstevel@tonic-gate #include <sys/types.h>
767c478bd9Sstevel@tonic-gate #include <dirent.h>
777c478bd9Sstevel@tonic-gate #include <fcntl.h>
787c478bd9Sstevel@tonic-gate #include <sys/stat.h>
797c478bd9Sstevel@tonic-gate #include <stdlib.h>
807c478bd9Sstevel@tonic-gate #include <ctype.h>
817c478bd9Sstevel@tonic-gate #include <string.h>
827c478bd9Sstevel@tonic-gate #include <stdio.h>
837c478bd9Sstevel@tonic-gate #include <unistd.h>
847c478bd9Sstevel@tonic-gate #include <thread.h>
857c478bd9Sstevel@tonic-gate #include <synch.h>
867c478bd9Sstevel@tonic-gate #include <errno.h>
877c478bd9Sstevel@tonic-gate #include <limits.h>
887c478bd9Sstevel@tonic-gate #include <sys/mkdev.h>
897c478bd9Sstevel@tonic-gate #include "tsd.h"
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate typedef struct entry {
927c478bd9Sstevel@tonic-gate 	char *name;
937c478bd9Sstevel@tonic-gate 	int flags;
947c478bd9Sstevel@tonic-gate } entry_t;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate typedef struct special {
977c478bd9Sstevel@tonic-gate 	const char *spcl_name;	/* device name */
987c478bd9Sstevel@tonic-gate 	dev_t spcl_rdev;	/* matching major/minor devnum */
997c478bd9Sstevel@tonic-gate 	dev_t spcl_fsdev;	/* devnum of containing FS */
1007c478bd9Sstevel@tonic-gate 	ino_t spcl_inum;	/* inum of entry in FS */
1017c478bd9Sstevel@tonic-gate } spcl_t;
1027c478bd9Sstevel@tonic-gate 
1037c478bd9Sstevel@tonic-gate static int srch_dir(const entry_t path, int match_mask, int depth,
1047c478bd9Sstevel@tonic-gate     const entry_t skip_dirs[], struct stat64 *fsb);
1057c478bd9Sstevel@tonic-gate static const entry_t *get_pri_dirs(void);
1067c478bd9Sstevel@tonic-gate static char *ispts(struct stat64 *fsb, int match_mask);
1077c478bd9Sstevel@tonic-gate static char *ispty(struct stat64 *fsb, int match_mask);
1087c478bd9Sstevel@tonic-gate static void itoa(int i, char *ptr);
1097c478bd9Sstevel@tonic-gate static char *_ttyname_common(struct stat64 *fsp, char *buffer,
1107c478bd9Sstevel@tonic-gate     uint_t match_mask);
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate #define	MAX_DEV_PATH	TTYNAME_MAX
1147c478bd9Sstevel@tonic-gate #define	MAX_SRCH_DEPTH	4
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate #define	MATCH_MM	1
1177c478bd9Sstevel@tonic-gate #define	MATCH_FS	2
1187c478bd9Sstevel@tonic-gate #define	MATCH_INO	4
1197c478bd9Sstevel@tonic-gate #define	MATCH_ALL	7
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate #define	DEV		"/dev"
1227c478bd9Sstevel@tonic-gate #define	TTYSRCH		"/etc/ttysrch"
1237c478bd9Sstevel@tonic-gate #define	PTS		"/dev/pts"
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate static const entry_t dev_dir =
1267c478bd9Sstevel@tonic-gate 	{ "/dev", MATCH_ALL };
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate static const entry_t def_srch_dirs[] = {	/* default search list */
1297c478bd9Sstevel@tonic-gate 	{ "/dev/pts", MATCH_ALL },
1307c478bd9Sstevel@tonic-gate 	{ "/dev/term", MATCH_ALL },
1317c478bd9Sstevel@tonic-gate 	{ "/dev/zcons", MATCH_ALL },
1327c478bd9Sstevel@tonic-gate 	{ NULL, 0 }
1337c478bd9Sstevel@tonic-gate };
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate static char *dir_buf;		/* directory buffer for ttysrch body */
1367c478bd9Sstevel@tonic-gate static entry_t *dir_vec;	/* directory vector for ttysrch ptrs */
1377c478bd9Sstevel@tonic-gate static size_t dir_size;		/* ttysrch file size */
1387c478bd9Sstevel@tonic-gate static timestruc_t dir_mtim;	/* ttysrch file modification time */
1397c478bd9Sstevel@tonic-gate static char rbuf[MAX_DEV_PATH]; /* perfect match file name */
1407c478bd9Sstevel@tonic-gate static char dev_rbuf[MAX_DEV_PATH]; /* partial match file name */
1417c478bd9Sstevel@tonic-gate static int dev_flag;		/* if set, dev + rdev match was found */
1427c478bd9Sstevel@tonic-gate static spcl_t special_case[] = {
1437c478bd9Sstevel@tonic-gate 	"/dev/tty", 0, 0, 0,
1447c478bd9Sstevel@tonic-gate 	"/dev/console", 0, 0, 0,
1457c478bd9Sstevel@tonic-gate 	"/dev/conslog", 0, 0, 0,
1467c478bd9Sstevel@tonic-gate 	"/dev/syscon", 0, 0, 0,
1477c478bd9Sstevel@tonic-gate 	"/dev/systty", 0, 0, 0,
1487c478bd9Sstevel@tonic-gate 	"/dev/wscons", 0, 0, 0
1497c478bd9Sstevel@tonic-gate };
1507c478bd9Sstevel@tonic-gate #define	NUMSPECIAL	(sizeof (special_case) / sizeof (spcl_t))
1517c478bd9Sstevel@tonic-gate static spcl_t ptmspecial = {
1527c478bd9Sstevel@tonic-gate 	"/dev/ptmx", 0, 0, 0
1537c478bd9Sstevel@tonic-gate };
1547c478bd9Sstevel@tonic-gate static	dev_t	ptcdev = NODEV;
1557c478bd9Sstevel@tonic-gate static	dev_t	ptsldev = NODEV;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate char *
1587c478bd9Sstevel@tonic-gate _ttyname_dev(dev_t rdev, char *buffer, size_t buflen)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	struct stat64 fsb;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	fsb.st_rdev = rdev;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	if (buflen < MAX_DEV_PATH) {
1657c478bd9Sstevel@tonic-gate 		errno = ERANGE;
1667c478bd9Sstevel@tonic-gate 		return (NULL);
1677c478bd9Sstevel@tonic-gate 	}
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	return (_ttyname_common(&fsb, buffer, MATCH_MM));
1707c478bd9Sstevel@tonic-gate }
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate /*
1737c478bd9Sstevel@tonic-gate  * POSIX.1c Draft-6 version of the function ttyname_r.
1747c478bd9Sstevel@tonic-gate  * It was implemented by Solaris 2.3.
1757c478bd9Sstevel@tonic-gate  */
1767c478bd9Sstevel@tonic-gate char *
1777c478bd9Sstevel@tonic-gate _ttyname_r(int f, char *buffer, int buflen)
1787c478bd9Sstevel@tonic-gate {
1797c478bd9Sstevel@tonic-gate 	struct stat64 fsb;	/* what we are searching for */
1807c478bd9Sstevel@tonic-gate 	/*
1817c478bd9Sstevel@tonic-gate 	 * do we need to search anything at all? (is fildes a char special tty
1827c478bd9Sstevel@tonic-gate 	 * file?)
1837c478bd9Sstevel@tonic-gate 	 */
1847c478bd9Sstevel@tonic-gate 	if (fstat64(f, &fsb) < 0) {
1857c478bd9Sstevel@tonic-gate 		errno = EBADF;
1867c478bd9Sstevel@tonic-gate 		return (0);
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate 	if ((isatty(f) == 0) ||
1897c478bd9Sstevel@tonic-gate 	    ((fsb.st_mode & S_IFMT) != S_IFCHR)) {
1907c478bd9Sstevel@tonic-gate 		errno = ENOTTY;
1917c478bd9Sstevel@tonic-gate 		return (0);
1927c478bd9Sstevel@tonic-gate 	}
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	if (buflen < MAX_DEV_PATH) {
1957c478bd9Sstevel@tonic-gate 		errno = ERANGE;
1967c478bd9Sstevel@tonic-gate 		return (0);
1977c478bd9Sstevel@tonic-gate 	}
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate 	return (_ttyname_common(&fsb, buffer, MATCH_ALL));
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate static char *
2037c478bd9Sstevel@tonic-gate _ttyname_common(struct stat64 *fsp, char *buffer, uint_t match_mask)
2047c478bd9Sstevel@tonic-gate {
2057c478bd9Sstevel@tonic-gate 	struct stat64 tfsb;
2067c478bd9Sstevel@tonic-gate 	const entry_t *srch_dirs;	/* priority directories */
2077c478bd9Sstevel@tonic-gate 	spcl_t *spclp;
2087c478bd9Sstevel@tonic-gate 	int i;
2097c478bd9Sstevel@tonic-gate 	int found = 0;
2107c478bd9Sstevel@tonic-gate 	int dirno = 0;
2117c478bd9Sstevel@tonic-gate 	int is_pts = 0;
2127c478bd9Sstevel@tonic-gate 	char *retval = NULL;
2137c478bd9Sstevel@tonic-gate 	char *pt = NULL;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 	/*
2167c478bd9Sstevel@tonic-gate 	 * We can't use lmutex_lock() here because we call malloc()/free()
2177c478bd9Sstevel@tonic-gate 	 * and _libc_gettext().  Use the brute-force fork_lock_enter().
2187c478bd9Sstevel@tonic-gate 	 */
2197c478bd9Sstevel@tonic-gate 	(void) fork_lock_enter(NULL);
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate 	/*
2227c478bd9Sstevel@tonic-gate 	 * match special cases
2237c478bd9Sstevel@tonic-gate 	 */
2247c478bd9Sstevel@tonic-gate 
2257c478bd9Sstevel@tonic-gate 	for (spclp = special_case, i = 0; i < NUMSPECIAL; spclp++, i++) {
2267c478bd9Sstevel@tonic-gate 		if ((spclp->spcl_inum | spclp->spcl_fsdev |
2277c478bd9Sstevel@tonic-gate 		    spclp->spcl_rdev) == 0) {
2287c478bd9Sstevel@tonic-gate 			if (stat64(spclp->spcl_name, &tfsb) != 0)
2297c478bd9Sstevel@tonic-gate 				continue;
2307c478bd9Sstevel@tonic-gate 			spclp->spcl_rdev = tfsb.st_rdev;
2317c478bd9Sstevel@tonic-gate 			spclp->spcl_fsdev = tfsb.st_dev;
2327c478bd9Sstevel@tonic-gate 			spclp->spcl_inum = tfsb.st_ino;
2337c478bd9Sstevel@tonic-gate 		}
2347c478bd9Sstevel@tonic-gate 		if (match_mask == MATCH_MM) {
2357c478bd9Sstevel@tonic-gate 			if (spclp->spcl_rdev == fsp->st_rdev) {
2367c478bd9Sstevel@tonic-gate 				retval = strcpy(rbuf, spclp->spcl_name);
2377c478bd9Sstevel@tonic-gate 				goto out;
2387c478bd9Sstevel@tonic-gate 			}
2397c478bd9Sstevel@tonic-gate 		} else if (spclp->spcl_fsdev == fsp->st_dev &&
2407c478bd9Sstevel@tonic-gate 		    spclp->spcl_rdev == fsp->st_rdev &&
2417c478bd9Sstevel@tonic-gate 		    spclp->spcl_inum == fsp->st_ino) {
2427c478bd9Sstevel@tonic-gate 			retval = strcpy(rbuf, spclp->spcl_name);
2437c478bd9Sstevel@tonic-gate 			goto out;
2447c478bd9Sstevel@tonic-gate 		}
2457c478bd9Sstevel@tonic-gate 	}
2467c478bd9Sstevel@tonic-gate 	/*
2477c478bd9Sstevel@tonic-gate 	 * additional special case: ptm clone device
2487c478bd9Sstevel@tonic-gate 	 *   ptm devs have no entries in /dev
2497c478bd9Sstevel@tonic-gate 	 *   if major number matches, just short circuit any further lookup
2507c478bd9Sstevel@tonic-gate 	 *   NOTE: the minor number of /dev/ptmx is the ptm major number
2517c478bd9Sstevel@tonic-gate 	 */
2527c478bd9Sstevel@tonic-gate 	spclp = &ptmspecial;
2537c478bd9Sstevel@tonic-gate 	if ((spclp->spcl_inum | spclp->spcl_fsdev | spclp->spcl_rdev) == 0) {
2547c478bd9Sstevel@tonic-gate 		if (stat64(spclp->spcl_name, &tfsb) == 0) {
2557c478bd9Sstevel@tonic-gate 			spclp->spcl_rdev = tfsb.st_rdev;
2567c478bd9Sstevel@tonic-gate 			spclp->spcl_fsdev = tfsb.st_dev;
2577c478bd9Sstevel@tonic-gate 			spclp->spcl_inum = tfsb.st_ino;
2587c478bd9Sstevel@tonic-gate 		}
2597c478bd9Sstevel@tonic-gate 	}
2607c478bd9Sstevel@tonic-gate 	if ((spclp->spcl_rdev != 0) &&
2617c478bd9Sstevel@tonic-gate 	    (minor(spclp->spcl_rdev) == major(fsp->st_rdev)))
2627c478bd9Sstevel@tonic-gate 		goto out;
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	/*
2657c478bd9Sstevel@tonic-gate 	 * additional special case: pty dev
2667c478bd9Sstevel@tonic-gate 	 *  one of the known default pairs of /dev/ptyXX or /dev/ttyXX
2677c478bd9Sstevel@tonic-gate 	 */
2687c478bd9Sstevel@tonic-gate 	if ((retval = ispty(fsp, match_mask)) != NULL)
2697c478bd9Sstevel@tonic-gate 		goto out;
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 	/*
2727c478bd9Sstevel@tonic-gate 	 * search the priority directories
2737c478bd9Sstevel@tonic-gate 	 */
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate 	srch_dirs = get_pri_dirs();
2777c478bd9Sstevel@tonic-gate 	dev_flag = 0;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	while ((!found) && (srch_dirs[dirno].name != NULL)) {
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 		/*
2827c478bd9Sstevel@tonic-gate 		 * if /dev is one of the priority directories, only
2837c478bd9Sstevel@tonic-gate 		 * search its top level(set depth = MAX_SEARCH_DEPTH)
2847c478bd9Sstevel@tonic-gate 		 */
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 		/*
2877c478bd9Sstevel@tonic-gate 		 * Is /dev/pts then just do a quick check. We don't have
2887c478bd9Sstevel@tonic-gate 		 * to stat the entire /dev/pts dir.
2897c478bd9Sstevel@tonic-gate 		 */
2907c478bd9Sstevel@tonic-gate 		if (strcmp(PTS, srch_dirs[dirno].name) == NULL) {
2917c478bd9Sstevel@tonic-gate 			if ((pt = ispts(fsp, match_mask)) != NULL) {
2927c478bd9Sstevel@tonic-gate 				is_pts = 1;
2937c478bd9Sstevel@tonic-gate 				found = 1;
2947c478bd9Sstevel@tonic-gate 			}
2957c478bd9Sstevel@tonic-gate 		} else {
2967c478bd9Sstevel@tonic-gate 			found = srch_dir(srch_dirs[dirno], match_mask,
2977c478bd9Sstevel@tonic-gate 				((strcmp(srch_dirs[dirno].name,
2987c478bd9Sstevel@tonic-gate 				dev_dir.name) == 0) ?
2997c478bd9Sstevel@tonic-gate 				MAX_SRCH_DEPTH : 1), 0, fsp);
3007c478bd9Sstevel@tonic-gate 		}
3017c478bd9Sstevel@tonic-gate 		dirno++;
3027c478bd9Sstevel@tonic-gate 	}
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	/*
3057c478bd9Sstevel@tonic-gate 	 * search the /dev/ directory, skipping priority directories
3067c478bd9Sstevel@tonic-gate 	 */
3077c478bd9Sstevel@tonic-gate 	if (!found)
3087c478bd9Sstevel@tonic-gate 		found = srch_dir(dev_dir, match_mask, 0, srch_dirs, fsp);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 
3117c478bd9Sstevel@tonic-gate 	/*
3127c478bd9Sstevel@tonic-gate 	 * return
3137c478bd9Sstevel@tonic-gate 	 */
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if (found) {
3167c478bd9Sstevel@tonic-gate 		if (is_pts)
3177c478bd9Sstevel@tonic-gate 			retval = pt;
3187c478bd9Sstevel@tonic-gate 		else
3197c478bd9Sstevel@tonic-gate 			retval = rbuf;
3207c478bd9Sstevel@tonic-gate 	} else if (dev_flag)
3217c478bd9Sstevel@tonic-gate 		retval = dev_rbuf;
3227c478bd9Sstevel@tonic-gate 	else
3237c478bd9Sstevel@tonic-gate 		retval = NULL;
3247c478bd9Sstevel@tonic-gate out:	retval = (retval ? strcpy(buffer, retval) : NULL);
3257c478bd9Sstevel@tonic-gate 	fork_lock_exit();
3267c478bd9Sstevel@tonic-gate 	return (retval);
3277c478bd9Sstevel@tonic-gate }
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate /*
3307c478bd9Sstevel@tonic-gate  * POSIX.1c standard version of the function ttyname_r.
3317c478bd9Sstevel@tonic-gate  * User gets it via static ttyname_r from the header file.
3327c478bd9Sstevel@tonic-gate  */
3337c478bd9Sstevel@tonic-gate int
3347c478bd9Sstevel@tonic-gate __posix_ttyname_r(int fildes, char *name, size_t namesize)
3357c478bd9Sstevel@tonic-gate {
3367c478bd9Sstevel@tonic-gate 	int nerrno = 0;
3377c478bd9Sstevel@tonic-gate 	int oerrno = errno;
3387c478bd9Sstevel@tonic-gate 	int namelen;
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	errno = 0;
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	if (namesize > INT_MAX)
3437c478bd9Sstevel@tonic-gate 		namelen = INT_MAX;
3447c478bd9Sstevel@tonic-gate 	else
3457c478bd9Sstevel@tonic-gate 		namelen = (int)namesize;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	if (_ttyname_r(fildes, name, namelen) == NULL) {
3487c478bd9Sstevel@tonic-gate 		if (errno == 0)
3497c478bd9Sstevel@tonic-gate 			nerrno = EINVAL;
3507c478bd9Sstevel@tonic-gate 		else
3517c478bd9Sstevel@tonic-gate 			nerrno = errno;
3527c478bd9Sstevel@tonic-gate 	}
3537c478bd9Sstevel@tonic-gate 	errno = oerrno;
3547c478bd9Sstevel@tonic-gate 	return (nerrno);
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /*
3587c478bd9Sstevel@tonic-gate  * Checks if the name is under /dev/pts directory
3597c478bd9Sstevel@tonic-gate  */
3607c478bd9Sstevel@tonic-gate static char *
3617c478bd9Sstevel@tonic-gate ispts(struct stat64 *fsb, int match_mask)
3627c478bd9Sstevel@tonic-gate {
3637c478bd9Sstevel@tonic-gate 	static  char	buf[MAX_DEV_PATH];
3647c478bd9Sstevel@tonic-gate 	struct	stat64	stb;
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	(void) strcpy(buf, "/dev/pts/");
3677c478bd9Sstevel@tonic-gate 	itoa(minor(fsb->st_rdev), buf+strlen(buf));
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	if (stat64(buf, &stb) != 0)
3707c478bd9Sstevel@tonic-gate 		return (NULL);
3717c478bd9Sstevel@tonic-gate 
3727c478bd9Sstevel@tonic-gate 	if (match_mask == MATCH_MM) {
3737c478bd9Sstevel@tonic-gate 		if (stb.st_rdev == fsb->st_rdev)
3747c478bd9Sstevel@tonic-gate 			return (buf);
3757c478bd9Sstevel@tonic-gate 	} else if (stb.st_rdev == fsb->st_rdev &&
3767c478bd9Sstevel@tonic-gate 		stb.st_dev == fsb->st_dev &&
3777c478bd9Sstevel@tonic-gate 		stb.st_ino == fsb->st_ino)
3787c478bd9Sstevel@tonic-gate 			return (buf);
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	return (NULL);
3817c478bd9Sstevel@tonic-gate }
3827c478bd9Sstevel@tonic-gate 
3837c478bd9Sstevel@tonic-gate /*
3847c478bd9Sstevel@tonic-gate  * Checks if the dev is a known pty master or slave device
3857c478bd9Sstevel@tonic-gate  */
3867c478bd9Sstevel@tonic-gate #define	MAXDEFAULTPTY	48
3877c478bd9Sstevel@tonic-gate 
3887c478bd9Sstevel@tonic-gate static char *
3897c478bd9Sstevel@tonic-gate ispty(struct stat64 *fsb, int match_mask)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	static char	buf[16];	/* big enough for "/dev/XtyXX" */
3927c478bd9Sstevel@tonic-gate 	struct	stat64	stb;
3937c478bd9Sstevel@tonic-gate 	minor_t dmin;
3947c478bd9Sstevel@tonic-gate 	char prefix;
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 	if (ptsldev == NODEV && stat64("/dev/ttyp0", &stb) == 0)
3977c478bd9Sstevel@tonic-gate 		ptsldev = stb.st_rdev;
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/*
4007c478bd9Sstevel@tonic-gate 	 * check for a ptsl dev (/dev/ttyXX)
4017c478bd9Sstevel@tonic-gate 	 */
4027c478bd9Sstevel@tonic-gate 	prefix = 't';
4037c478bd9Sstevel@tonic-gate 	if (major(fsb->st_rdev) != major(ptsldev)) {
4047c478bd9Sstevel@tonic-gate 		/*
4057c478bd9Sstevel@tonic-gate 		 * not a ptsl, check for a ptc
4067c478bd9Sstevel@tonic-gate 		 */
4077c478bd9Sstevel@tonic-gate 		if (ptcdev == NODEV && stat64("/dev/ptyp0", &stb) == 0)
4087c478bd9Sstevel@tonic-gate 			ptcdev = stb.st_rdev;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 		/*
4117c478bd9Sstevel@tonic-gate 		 * check for a ptc dev (/dev/ptyXX)
4127c478bd9Sstevel@tonic-gate 		 */
4137c478bd9Sstevel@tonic-gate 		prefix = 'p';
4147c478bd9Sstevel@tonic-gate 		if (major(fsb->st_rdev) != major(ptcdev))
4157c478bd9Sstevel@tonic-gate 			return (NULL);
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 	/*
4197c478bd9Sstevel@tonic-gate 	 * check if minor number is in the known range
4207c478bd9Sstevel@tonic-gate 	 */
4217c478bd9Sstevel@tonic-gate 	dmin = minor(fsb->st_rdev);
4227c478bd9Sstevel@tonic-gate 	if (dmin > MAXDEFAULTPTY)
4237c478bd9Sstevel@tonic-gate 		return (NULL);
4247c478bd9Sstevel@tonic-gate 
4257c478bd9Sstevel@tonic-gate 	/*
4267c478bd9Sstevel@tonic-gate 	 * modify name based on minor number
4277c478bd9Sstevel@tonic-gate 	 */
4287c478bd9Sstevel@tonic-gate 	(void) snprintf(buf, sizeof (buf), "/dev/%cty%c%c",
4297c478bd9Sstevel@tonic-gate 	    prefix, 'p' + dmin / 16, "0123456789abcdef"[dmin % 16]);
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if (stat64(buf, &stb) != 0)
4327c478bd9Sstevel@tonic-gate 		return (NULL);
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 	if (match_mask == MATCH_MM) {
4357c478bd9Sstevel@tonic-gate 		if (stb.st_rdev == fsb->st_rdev)
4367c478bd9Sstevel@tonic-gate 			return (buf);
4377c478bd9Sstevel@tonic-gate 	} else if (stb.st_rdev == fsb->st_rdev &&
4387c478bd9Sstevel@tonic-gate 		stb.st_dev == fsb->st_dev &&
4397c478bd9Sstevel@tonic-gate 		stb.st_ino == fsb->st_ino)
4407c478bd9Sstevel@tonic-gate 			return (buf);
4417c478bd9Sstevel@tonic-gate 
4427c478bd9Sstevel@tonic-gate 	return (NULL);
4437c478bd9Sstevel@tonic-gate }
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate /*
4477c478bd9Sstevel@tonic-gate  * Converts a number to a string (null terminated).
4487c478bd9Sstevel@tonic-gate  */
4497c478bd9Sstevel@tonic-gate static void
4507c478bd9Sstevel@tonic-gate itoa(int i, char *ptr)
4517c478bd9Sstevel@tonic-gate {
4527c478bd9Sstevel@tonic-gate 	int dig = 0;
4537c478bd9Sstevel@tonic-gate 	int tempi;
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	tempi = i;
4567c478bd9Sstevel@tonic-gate 	do {
4577c478bd9Sstevel@tonic-gate 		dig++;
4587c478bd9Sstevel@tonic-gate 		tempi /= 10;
4597c478bd9Sstevel@tonic-gate 	} while (tempi);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	ptr += dig;
4627c478bd9Sstevel@tonic-gate 	*ptr = '\0';
4637c478bd9Sstevel@tonic-gate 	while (--dig >= 0) {
4647c478bd9Sstevel@tonic-gate 		*(--ptr) = i % 10 + '0';
4657c478bd9Sstevel@tonic-gate 		i /= 10;
4667c478bd9Sstevel@tonic-gate 	}
4677c478bd9Sstevel@tonic-gate }
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate /*
4707c478bd9Sstevel@tonic-gate  * srch_dir() searches directory path and all directories under it up
4717c478bd9Sstevel@tonic-gate  * to depth directories deep for a file described by a stat structure
4727c478bd9Sstevel@tonic-gate  * fsb.  It puts the answer into rbuf.  If a match is found on device
4737c478bd9Sstevel@tonic-gate  * number only, the file name is put into dev_rbuf and dev_flag is set.
4747c478bd9Sstevel@tonic-gate  *
4757c478bd9Sstevel@tonic-gate  * srch_dir() returns 1 if a match (on device and inode) is found,
4767c478bd9Sstevel@tonic-gate  * or 0 otherwise.
4777c478bd9Sstevel@tonic-gate  *
4787c478bd9Sstevel@tonic-gate  */
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate static int
4817c478bd9Sstevel@tonic-gate srch_dir(const entry_t path,	/* current path */
4827c478bd9Sstevel@tonic-gate 	int match_mask,		/* flags mask */
4837c478bd9Sstevel@tonic-gate 	int depth,		/* current depth (/dev = 0) */
4847c478bd9Sstevel@tonic-gate 	const entry_t skip_dirs[], /* directories not needing searching */
4857c478bd9Sstevel@tonic-gate 	struct stat64 *fsb)	/* the file being searched for */
4867c478bd9Sstevel@tonic-gate {
4877c478bd9Sstevel@tonic-gate 	DIR *dirp;
4887c478bd9Sstevel@tonic-gate 	struct dirent64 *direntp;
4897c478bd9Sstevel@tonic-gate 	struct stat64 tsb;
4907c478bd9Sstevel@tonic-gate 	char file_name[MAX_DEV_PATH];
4917c478bd9Sstevel@tonic-gate 	entry_t file;
4927c478bd9Sstevel@tonic-gate 	char *last_comp;
4937c478bd9Sstevel@tonic-gate 	int found = 0;
4947c478bd9Sstevel@tonic-gate 	int dirno = 0;
4957c478bd9Sstevel@tonic-gate 	size_t path_len;
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	file.name = file_name;
4987c478bd9Sstevel@tonic-gate 	file.flags = path.flags & match_mask;
4997c478bd9Sstevel@tonic-gate 	if (file.flags == 0)
5007c478bd9Sstevel@tonic-gate 		file.flags = match_mask;
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	/*
5037c478bd9Sstevel@tonic-gate 	 * do we need to search this directory? (always search /dev at depth 0)
5047c478bd9Sstevel@tonic-gate 	 */
5057c478bd9Sstevel@tonic-gate 	if ((skip_dirs != NULL) && (depth != 0))
5067c478bd9Sstevel@tonic-gate 		while (skip_dirs[dirno].name != NULL)
5077c478bd9Sstevel@tonic-gate 			if (strcmp(skip_dirs[dirno++].name, path.name) == 0)
5087c478bd9Sstevel@tonic-gate 				return (0);
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	/*
5117c478bd9Sstevel@tonic-gate 	 * open directory
5127c478bd9Sstevel@tonic-gate 	 */
5137c478bd9Sstevel@tonic-gate 	if ((dirp = opendir(path.name)) == NULL) {
5147c478bd9Sstevel@tonic-gate 		return (0);
5157c478bd9Sstevel@tonic-gate 	}
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	path_len = strlen(path.name);
5187c478bd9Sstevel@tonic-gate 	(void) strcpy(file_name, path.name);
5197c478bd9Sstevel@tonic-gate 	last_comp = file_name + path_len;
5207c478bd9Sstevel@tonic-gate 	*last_comp++ = '/';
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate 	/*
5237c478bd9Sstevel@tonic-gate 	 * read thru the directory
5247c478bd9Sstevel@tonic-gate 	 */
5257c478bd9Sstevel@tonic-gate 	while ((!found) && ((direntp = readdir64(dirp)) != NULL)) {
526*13b62818Sraf 		/*
527*13b62818Sraf 		 * skip "." and ".." entries, if present
528*13b62818Sraf 		 */
529*13b62818Sraf 		if (direntp->d_name[0] == '.' &&
530*13b62818Sraf 		    (strcmp(direntp->d_name, ".") == 0 ||
531*13b62818Sraf 		    strcmp(direntp->d_name, "..") == 0))
532*13b62818Sraf 			continue;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 		/*
5357c478bd9Sstevel@tonic-gate 		 * if the file name (path + "/" + d_name + NULL) would be too
5367c478bd9Sstevel@tonic-gate 		 * long, skip it
5377c478bd9Sstevel@tonic-gate 		 */
5387c478bd9Sstevel@tonic-gate 		if ((path_len + strlen(direntp->d_name) + 2) > MAX_DEV_PATH)
5397c478bd9Sstevel@tonic-gate 			continue;
5407c478bd9Sstevel@tonic-gate 
541*13b62818Sraf 		(void) strcpy(last_comp, direntp->d_name);
5427c478bd9Sstevel@tonic-gate 		if (stat64(file_name, &tsb) < 0)
5437c478bd9Sstevel@tonic-gate 			continue;
5447c478bd9Sstevel@tonic-gate 
5457c478bd9Sstevel@tonic-gate 		/*
5467c478bd9Sstevel@tonic-gate 		 * if a file is a directory and we are not too deep, recurse
5477c478bd9Sstevel@tonic-gate 		 */
5487c478bd9Sstevel@tonic-gate 		if ((tsb.st_mode & S_IFMT) == S_IFDIR)
5497c478bd9Sstevel@tonic-gate 			if (depth < MAX_SRCH_DEPTH)
5507c478bd9Sstevel@tonic-gate 				found = srch_dir(file, match_mask, depth+1,
5517c478bd9Sstevel@tonic-gate 						skip_dirs, fsb);
5527c478bd9Sstevel@tonic-gate 			else
5537c478bd9Sstevel@tonic-gate 				continue;
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 		/*
5567c478bd9Sstevel@tonic-gate 		 * else if it is not a directory, is it a character special
5577c478bd9Sstevel@tonic-gate 		 * file?
5587c478bd9Sstevel@tonic-gate 		 */
5597c478bd9Sstevel@tonic-gate 		else if ((tsb.st_mode & S_IFMT) == S_IFCHR) {
5607c478bd9Sstevel@tonic-gate 			int flag = 0;
5617c478bd9Sstevel@tonic-gate 			if (tsb.st_dev == fsb->st_dev)
5627c478bd9Sstevel@tonic-gate 				flag |= MATCH_FS;
5637c478bd9Sstevel@tonic-gate 			if (tsb.st_rdev == fsb->st_rdev)
5647c478bd9Sstevel@tonic-gate 				flag |= MATCH_MM;
5657c478bd9Sstevel@tonic-gate 			if (tsb.st_ino == fsb->st_ino)
5667c478bd9Sstevel@tonic-gate 				flag |= MATCH_INO;
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 			if ((flag & file.flags) == file.flags) {
5697c478bd9Sstevel@tonic-gate 				(void) strcpy(rbuf, file.name);
5707c478bd9Sstevel@tonic-gate 				found = 1;
5717c478bd9Sstevel@tonic-gate 			} else if ((flag & (MATCH_MM | MATCH_FS)) ==
5727c478bd9Sstevel@tonic-gate 					(MATCH_MM | MATCH_FS)) {
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 				/*
5757c478bd9Sstevel@tonic-gate 				 * no (inodes do not match), but save the name
5767c478bd9Sstevel@tonic-gate 				 * for later
5777c478bd9Sstevel@tonic-gate 				 */
5787c478bd9Sstevel@tonic-gate 				(void) strcpy(dev_rbuf, file.name);
5797c478bd9Sstevel@tonic-gate 				dev_flag = 1;
5807c478bd9Sstevel@tonic-gate 			}
5817c478bd9Sstevel@tonic-gate 		}
5827c478bd9Sstevel@tonic-gate 	}
5837c478bd9Sstevel@tonic-gate 	(void) closedir(dirp);
5847c478bd9Sstevel@tonic-gate 	return (found);
5857c478bd9Sstevel@tonic-gate }
5867c478bd9Sstevel@tonic-gate 
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate /*
5897c478bd9Sstevel@tonic-gate  * get_pri_dirs() - returns a pointer to an array of strings, where each string
5907c478bd9Sstevel@tonic-gate  * is a priority directory name.  The end of the array is marked by a NULL
5917c478bd9Sstevel@tonic-gate  * pointer.  The priority directories' names are obtained from the file
5927c478bd9Sstevel@tonic-gate  * /etc/ttysrch if it exists and is readable, or if not, a default hard-coded
5937c478bd9Sstevel@tonic-gate  * list of directories.
5947c478bd9Sstevel@tonic-gate  *
5957c478bd9Sstevel@tonic-gate  * /etc/ttysrch, if used, is read in as a string of characters into memory and
5967c478bd9Sstevel@tonic-gate  * then parsed into strings of priority directory names, omitting comments and
5977c478bd9Sstevel@tonic-gate  * blank lines.
5987c478bd9Sstevel@tonic-gate  *
5997c478bd9Sstevel@tonic-gate  */
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate #define	START_STATE	1
6027c478bd9Sstevel@tonic-gate #define	COMMENT_STATE	2
6037c478bd9Sstevel@tonic-gate #define	DIRNAME_STATE	3
6047c478bd9Sstevel@tonic-gate #define	FLAG_STATE	4
6057c478bd9Sstevel@tonic-gate #define	CHECK_STATE	5
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate #define	COMMENT_CHAR	'#'
6087c478bd9Sstevel@tonic-gate #define	EOLN_CHAR	'\n'
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate static const entry_t *
6117c478bd9Sstevel@tonic-gate get_pri_dirs(void)
6127c478bd9Sstevel@tonic-gate {
6137c478bd9Sstevel@tonic-gate 	int fd, state;
6147c478bd9Sstevel@tonic-gate 	size_t sz;
6157c478bd9Sstevel@tonic-gate 	ssize_t size;
6167c478bd9Sstevel@tonic-gate 	struct stat64 sb;
6177c478bd9Sstevel@tonic-gate 	char *buf, *ebuf;
6187c478bd9Sstevel@tonic-gate 	entry_t *vec;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	/*
6217c478bd9Sstevel@tonic-gate 	 * if no /etc/ttysrch, use defaults
6227c478bd9Sstevel@tonic-gate 	 */
6237c478bd9Sstevel@tonic-gate 	if ((fd = open(TTYSRCH, 0)) < 0)
6247c478bd9Sstevel@tonic-gate 		return (def_srch_dirs);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (fstat64(fd, &sb) < 0) {
6277c478bd9Sstevel@tonic-gate 		(void) close(fd);
6287c478bd9Sstevel@tonic-gate 		return (def_srch_dirs);
6297c478bd9Sstevel@tonic-gate 	}
6307c478bd9Sstevel@tonic-gate 
6317c478bd9Sstevel@tonic-gate 	sz = (size_t)sb.st_size;
6327c478bd9Sstevel@tonic-gate 	if (dir_vec != NULL && sz == dir_size &&
6337c478bd9Sstevel@tonic-gate 	    sb.st_mtim.tv_sec == dir_mtim.tv_sec &&
6347c478bd9Sstevel@tonic-gate 	    sb.st_mtim.tv_nsec == dir_mtim.tv_nsec) {
6357c478bd9Sstevel@tonic-gate 		/*
6367c478bd9Sstevel@tonic-gate 		 * size & modification time match
6377c478bd9Sstevel@tonic-gate 		 * no need to reread TTYSRCH
6387c478bd9Sstevel@tonic-gate 		 * just return old pointer
6397c478bd9Sstevel@tonic-gate 		 */
6407c478bd9Sstevel@tonic-gate 		(void) close(fd);
6417c478bd9Sstevel@tonic-gate 		return (dir_vec);
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 	buf = realloc(dir_buf, sz + 1);
6447c478bd9Sstevel@tonic-gate 	if (buf != NULL) {
6457c478bd9Sstevel@tonic-gate 		dir_buf = buf;
6467c478bd9Sstevel@tonic-gate 		size = read(fd, dir_buf, sz);
6477c478bd9Sstevel@tonic-gate 	}
6487c478bd9Sstevel@tonic-gate 	(void) close(fd);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	if (buf == NULL || size < 0) {
6517c478bd9Sstevel@tonic-gate 		if (dir_vec != NULL) {
6527c478bd9Sstevel@tonic-gate 			free(dir_vec);
6537c478bd9Sstevel@tonic-gate 			dir_vec = NULL;
6547c478bd9Sstevel@tonic-gate 		}
6557c478bd9Sstevel@tonic-gate 		return ((entry_t *)def_srch_dirs);
6567c478bd9Sstevel@tonic-gate 	}
6577c478bd9Sstevel@tonic-gate 	dir_size = sz;
6587c478bd9Sstevel@tonic-gate 	dir_mtim = sb.st_mtim;
6597c478bd9Sstevel@tonic-gate 
6607c478bd9Sstevel@tonic-gate 	/*
6617c478bd9Sstevel@tonic-gate 	 * ensure newline termination for buffer.  Add an extra
6627c478bd9Sstevel@tonic-gate 	 * entry to dir_vec for null terminator
6637c478bd9Sstevel@tonic-gate 	 */
6647c478bd9Sstevel@tonic-gate 	ebuf = &dir_buf[size];
6657c478bd9Sstevel@tonic-gate 	*ebuf++ = '\n';
6667c478bd9Sstevel@tonic-gate 	for (sz = 1, buf = dir_buf; buf < ebuf; ++buf)
6677c478bd9Sstevel@tonic-gate 		if (*buf == '\n')
6687c478bd9Sstevel@tonic-gate 			++sz;
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	sz *= sizeof (*dir_vec);
6717c478bd9Sstevel@tonic-gate 	vec = realloc(dir_vec, sz);
6727c478bd9Sstevel@tonic-gate 	if (vec == NULL) {
6737c478bd9Sstevel@tonic-gate 		if (dir_vec != NULL) {
6747c478bd9Sstevel@tonic-gate 			free(dir_vec);
6757c478bd9Sstevel@tonic-gate 			dir_vec = NULL;
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 		return (def_srch_dirs);
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 	dir_vec = vec;
6807c478bd9Sstevel@tonic-gate 	state = START_STATE;
6817c478bd9Sstevel@tonic-gate 	for (buf = dir_buf; buf < ebuf; ++buf) {
6827c478bd9Sstevel@tonic-gate 		switch (state) {
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate 		case START_STATE:
6857c478bd9Sstevel@tonic-gate 			if (*buf == COMMENT_CHAR) {
6867c478bd9Sstevel@tonic-gate 				state = COMMENT_STATE;
6877c478bd9Sstevel@tonic-gate 				break;
6887c478bd9Sstevel@tonic-gate 			}
6897c478bd9Sstevel@tonic-gate 			if (!isspace(*buf))	/* skip leading white space */
6907c478bd9Sstevel@tonic-gate 				state = DIRNAME_STATE;
6917c478bd9Sstevel@tonic-gate 				vec->name = buf;
6927c478bd9Sstevel@tonic-gate 				vec->flags = 0;
6937c478bd9Sstevel@tonic-gate 			break;
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 		case COMMENT_STATE:
6967c478bd9Sstevel@tonic-gate 			if (*buf == EOLN_CHAR)
6977c478bd9Sstevel@tonic-gate 				state = START_STATE;
6987c478bd9Sstevel@tonic-gate 			break;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 		case DIRNAME_STATE:
7017c478bd9Sstevel@tonic-gate 			if (*buf == EOLN_CHAR) {
7027c478bd9Sstevel@tonic-gate 				state = CHECK_STATE;
7037c478bd9Sstevel@tonic-gate 				*buf = '\0';
7047c478bd9Sstevel@tonic-gate 			} else if (isspace(*buf)) {
7057c478bd9Sstevel@tonic-gate 				/* skip trailing white space */
7067c478bd9Sstevel@tonic-gate 				state = FLAG_STATE;
7077c478bd9Sstevel@tonic-gate 				*buf = '\0';
7087c478bd9Sstevel@tonic-gate 			}
7097c478bd9Sstevel@tonic-gate 			break;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		case FLAG_STATE:
7127c478bd9Sstevel@tonic-gate 			switch (*buf) {
7137c478bd9Sstevel@tonic-gate 				case 'M':
7147c478bd9Sstevel@tonic-gate 					vec->flags |= MATCH_MM;
7157c478bd9Sstevel@tonic-gate 					break;
7167c478bd9Sstevel@tonic-gate 				case 'F':
7177c478bd9Sstevel@tonic-gate 					vec->flags |= MATCH_FS;
7187c478bd9Sstevel@tonic-gate 					break;
7197c478bd9Sstevel@tonic-gate 				case 'I':
7207c478bd9Sstevel@tonic-gate 					vec->flags |= MATCH_INO;
7217c478bd9Sstevel@tonic-gate 					break;
7227c478bd9Sstevel@tonic-gate 				case EOLN_CHAR:
7237c478bd9Sstevel@tonic-gate 					state = CHECK_STATE;
7247c478bd9Sstevel@tonic-gate 					break;
7257c478bd9Sstevel@tonic-gate 			}
7267c478bd9Sstevel@tonic-gate 			break;
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate 		case CHECK_STATE:
7297c478bd9Sstevel@tonic-gate 			if (strncmp(vec->name, DEV, strlen(DEV)) != 0) {
7307c478bd9Sstevel@tonic-gate 				int tfd = open("/dev/console", O_WRONLY);
7317c478bd9Sstevel@tonic-gate 				if (tfd >= 0) {
7327c478bd9Sstevel@tonic-gate 					char buf[256];
7337c478bd9Sstevel@tonic-gate 					/* LINTED variable format specifier */
7347c478bd9Sstevel@tonic-gate 					(void) snprintf(buf, sizeof (buf),
7357c478bd9Sstevel@tonic-gate 						_libc_gettext(
7367c478bd9Sstevel@tonic-gate "ERROR: Entry '%s' in /etc/ttysrch ignored.\n"),
7377c478bd9Sstevel@tonic-gate 						vec->name);
7387c478bd9Sstevel@tonic-gate 					(void) write(tfd, buf, strlen(buf));
7397c478bd9Sstevel@tonic-gate 					(void) close(tfd);
7407c478bd9Sstevel@tonic-gate 				}
7417c478bd9Sstevel@tonic-gate 			} else {
7427c478bd9Sstevel@tonic-gate 				char *slash;
7437c478bd9Sstevel@tonic-gate 				slash = vec->name + strlen(vec->name) - 1;
7447c478bd9Sstevel@tonic-gate 				while (*slash == '/')
7457c478bd9Sstevel@tonic-gate 					*slash-- = '\0';
7467c478bd9Sstevel@tonic-gate 				if (vec->flags == 0)
7477c478bd9Sstevel@tonic-gate 					vec->flags = MATCH_ALL;
7487c478bd9Sstevel@tonic-gate 				vec++;
7497c478bd9Sstevel@tonic-gate 			}
7507c478bd9Sstevel@tonic-gate 			state = START_STATE;
7517c478bd9Sstevel@tonic-gate 			/*
7527c478bd9Sstevel@tonic-gate 			 * This state does not consume a character, so
7537c478bd9Sstevel@tonic-gate 			 * reposition the pointer.
7547c478bd9Sstevel@tonic-gate 			 */
7557c478bd9Sstevel@tonic-gate 			buf--;
7567c478bd9Sstevel@tonic-gate 			break;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 		}
7597c478bd9Sstevel@tonic-gate 	}
7607c478bd9Sstevel@tonic-gate 	vec->name = NULL;
7617c478bd9Sstevel@tonic-gate 	return (dir_vec);
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate char *
7667c478bd9Sstevel@tonic-gate ttyname(int f)
7677c478bd9Sstevel@tonic-gate {
7687c478bd9Sstevel@tonic-gate 	char *ans = tsdalloc(_T_TTYNAME, MAX_DEV_PATH, NULL);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	if (ans == NULL)
7717c478bd9Sstevel@tonic-gate 		return (NULL);
7727c478bd9Sstevel@tonic-gate 	return (_ttyname_r(f, ans, MAX_DEV_PATH));
7737c478bd9Sstevel@tonic-gate }
774