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