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