1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate /* Copyright (c) 1988 AT&T */ 30*0Sstevel@tonic-gate /* All Rights Reserved */ 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate 33*0Sstevel@tonic-gate /* 34*0Sstevel@tonic-gate * ttyname(f): return "/dev/X" (where X is a relative pathname 35*0Sstevel@tonic-gate * under /dev/), which is the name of the tty character special 36*0Sstevel@tonic-gate * file associated with the file descriptor f, or NULL if the 37*0Sstevel@tonic-gate * pathname cannot be found. 38*0Sstevel@tonic-gate * 39*0Sstevel@tonic-gate * Ttyname tries to find the tty file by matching major/minor 40*0Sstevel@tonic-gate * device, file system ID, and inode numbers of the file 41*0Sstevel@tonic-gate * descriptor parameter to those of files in the /dev/ directory. 42*0Sstevel@tonic-gate * 43*0Sstevel@tonic-gate * It attempts to find a match on major/minor device numbers, 44*0Sstevel@tonic-gate * file system ID, and inode numbers, but failing to match on 45*0Sstevel@tonic-gate * all three, settles for just a match on device numbers and 46*0Sstevel@tonic-gate * file system ID. 47*0Sstevel@tonic-gate * 48*0Sstevel@tonic-gate * To achieve higher performance and more flexible functionality, 49*0Sstevel@tonic-gate * ttyname first looks for the tty file in the directories specified 50*0Sstevel@tonic-gate * in the configuration file /etc/ttysrch. Entries in /etc/ttysrch 51*0Sstevel@tonic-gate * may be qualified to specify that a partial match may be acceptable. 52*0Sstevel@tonic-gate * This further improves performance by allowing an entry which 53*0Sstevel@tonic-gate * matches major/minor and file system ID, but not inode number 54*0Sstevel@tonic-gate * without searching the entire /dev tree. If /etc/ttysrch does not 55*0Sstevel@tonic-gate * exist, ttyname looks in a default list of directories. If after 56*0Sstevel@tonic-gate * looking in the most likely places, ttyname still cannot find the 57*0Sstevel@tonic-gate * tty file, it recursively searches thru the rest of the /dev/ 58*0Sstevel@tonic-gate * directory. 59*0Sstevel@tonic-gate * 60*0Sstevel@tonic-gate * In addition to the public interfaces, ttyname() & ttyname_r(), which 61*0Sstevel@tonic-gate * do the lookup based on an open file descriptor, 62*0Sstevel@tonic-gate * the private interface _ttyname_dev() does the lookup based on a 63*0Sstevel@tonic-gate * major/minor device. It follows the same order of lookup rules and 64*0Sstevel@tonic-gate * returns similar information, but matches on just the major/minor 65*0Sstevel@tonic-gate * device numbers. 66*0Sstevel@tonic-gate */ 67*0Sstevel@tonic-gate 68*0Sstevel@tonic-gate #pragma weak ttyname = _ttyname 69*0Sstevel@tonic-gate #pragma weak ttyname_r = _ttyname_r 70*0Sstevel@tonic-gate 71*0Sstevel@tonic-gate #include "synonyms.h" 72*0Sstevel@tonic-gate #include "mtlib.h" 73*0Sstevel@tonic-gate #include "libc.h" 74*0Sstevel@tonic-gate #include "_libc_gettext.h" 75*0Sstevel@tonic-gate #include <sys/sysmacros.h> 76*0Sstevel@tonic-gate #include <sys/types.h> 77*0Sstevel@tonic-gate #include <dirent.h> 78*0Sstevel@tonic-gate #include <fcntl.h> 79*0Sstevel@tonic-gate #include <sys/stat.h> 80*0Sstevel@tonic-gate #include <stdlib.h> 81*0Sstevel@tonic-gate #include <ctype.h> 82*0Sstevel@tonic-gate #include <string.h> 83*0Sstevel@tonic-gate #include <stdio.h> 84*0Sstevel@tonic-gate #include <unistd.h> 85*0Sstevel@tonic-gate #include <thread.h> 86*0Sstevel@tonic-gate #include <synch.h> 87*0Sstevel@tonic-gate #include <errno.h> 88*0Sstevel@tonic-gate #include <limits.h> 89*0Sstevel@tonic-gate #include <sys/mkdev.h> 90*0Sstevel@tonic-gate #include "tsd.h" 91*0Sstevel@tonic-gate 92*0Sstevel@tonic-gate typedef struct entry { 93*0Sstevel@tonic-gate char *name; 94*0Sstevel@tonic-gate int flags; 95*0Sstevel@tonic-gate } entry_t; 96*0Sstevel@tonic-gate 97*0Sstevel@tonic-gate typedef struct special { 98*0Sstevel@tonic-gate const char *spcl_name; /* device name */ 99*0Sstevel@tonic-gate dev_t spcl_rdev; /* matching major/minor devnum */ 100*0Sstevel@tonic-gate dev_t spcl_fsdev; /* devnum of containing FS */ 101*0Sstevel@tonic-gate ino_t spcl_inum; /* inum of entry in FS */ 102*0Sstevel@tonic-gate } spcl_t; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate static int srch_dir(const entry_t path, int match_mask, int depth, 105*0Sstevel@tonic-gate const entry_t skip_dirs[], struct stat64 *fsb); 106*0Sstevel@tonic-gate static const entry_t *get_pri_dirs(void); 107*0Sstevel@tonic-gate static char *ispts(struct stat64 *fsb, int match_mask); 108*0Sstevel@tonic-gate static char *ispty(struct stat64 *fsb, int match_mask); 109*0Sstevel@tonic-gate static void itoa(int i, char *ptr); 110*0Sstevel@tonic-gate static char *_ttyname_common(struct stat64 *fsp, char *buffer, 111*0Sstevel@tonic-gate uint_t match_mask); 112*0Sstevel@tonic-gate 113*0Sstevel@tonic-gate 114*0Sstevel@tonic-gate #define MAX_DEV_PATH TTYNAME_MAX 115*0Sstevel@tonic-gate #define MAX_SRCH_DEPTH 4 116*0Sstevel@tonic-gate 117*0Sstevel@tonic-gate #define MATCH_MM 1 118*0Sstevel@tonic-gate #define MATCH_FS 2 119*0Sstevel@tonic-gate #define MATCH_INO 4 120*0Sstevel@tonic-gate #define MATCH_ALL 7 121*0Sstevel@tonic-gate 122*0Sstevel@tonic-gate #define DEV "/dev" 123*0Sstevel@tonic-gate #define TTYSRCH "/etc/ttysrch" 124*0Sstevel@tonic-gate #define PTS "/dev/pts" 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate static const entry_t dev_dir = 127*0Sstevel@tonic-gate { "/dev", MATCH_ALL }; 128*0Sstevel@tonic-gate 129*0Sstevel@tonic-gate static const entry_t def_srch_dirs[] = { /* default search list */ 130*0Sstevel@tonic-gate { "/dev/pts", MATCH_ALL }, 131*0Sstevel@tonic-gate { "/dev/term", MATCH_ALL }, 132*0Sstevel@tonic-gate { "/dev/zcons", MATCH_ALL }, 133*0Sstevel@tonic-gate { NULL, 0 } 134*0Sstevel@tonic-gate }; 135*0Sstevel@tonic-gate 136*0Sstevel@tonic-gate static char *dir_buf; /* directory buffer for ttysrch body */ 137*0Sstevel@tonic-gate static entry_t *dir_vec; /* directory vector for ttysrch ptrs */ 138*0Sstevel@tonic-gate static size_t dir_size; /* ttysrch file size */ 139*0Sstevel@tonic-gate static timestruc_t dir_mtim; /* ttysrch file modification time */ 140*0Sstevel@tonic-gate static char rbuf[MAX_DEV_PATH]; /* perfect match file name */ 141*0Sstevel@tonic-gate static char dev_rbuf[MAX_DEV_PATH]; /* partial match file name */ 142*0Sstevel@tonic-gate static int dev_flag; /* if set, dev + rdev match was found */ 143*0Sstevel@tonic-gate static spcl_t special_case[] = { 144*0Sstevel@tonic-gate "/dev/tty", 0, 0, 0, 145*0Sstevel@tonic-gate "/dev/console", 0, 0, 0, 146*0Sstevel@tonic-gate "/dev/conslog", 0, 0, 0, 147*0Sstevel@tonic-gate "/dev/syscon", 0, 0, 0, 148*0Sstevel@tonic-gate "/dev/systty", 0, 0, 0, 149*0Sstevel@tonic-gate "/dev/wscons", 0, 0, 0 150*0Sstevel@tonic-gate }; 151*0Sstevel@tonic-gate #define NUMSPECIAL (sizeof (special_case) / sizeof (spcl_t)) 152*0Sstevel@tonic-gate static spcl_t ptmspecial = { 153*0Sstevel@tonic-gate "/dev/ptmx", 0, 0, 0 154*0Sstevel@tonic-gate }; 155*0Sstevel@tonic-gate static dev_t ptcdev = NODEV; 156*0Sstevel@tonic-gate static dev_t ptsldev = NODEV; 157*0Sstevel@tonic-gate 158*0Sstevel@tonic-gate char * 159*0Sstevel@tonic-gate _ttyname_dev(dev_t rdev, char *buffer, size_t buflen) 160*0Sstevel@tonic-gate { 161*0Sstevel@tonic-gate struct stat64 fsb; 162*0Sstevel@tonic-gate 163*0Sstevel@tonic-gate fsb.st_rdev = rdev; 164*0Sstevel@tonic-gate 165*0Sstevel@tonic-gate if (buflen < MAX_DEV_PATH) { 166*0Sstevel@tonic-gate errno = ERANGE; 167*0Sstevel@tonic-gate return (NULL); 168*0Sstevel@tonic-gate } 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate return (_ttyname_common(&fsb, buffer, MATCH_MM)); 171*0Sstevel@tonic-gate } 172*0Sstevel@tonic-gate 173*0Sstevel@tonic-gate /* 174*0Sstevel@tonic-gate * POSIX.1c Draft-6 version of the function ttyname_r. 175*0Sstevel@tonic-gate * It was implemented by Solaris 2.3. 176*0Sstevel@tonic-gate */ 177*0Sstevel@tonic-gate char * 178*0Sstevel@tonic-gate _ttyname_r(int f, char *buffer, int buflen) 179*0Sstevel@tonic-gate { 180*0Sstevel@tonic-gate struct stat64 fsb; /* what we are searching for */ 181*0Sstevel@tonic-gate /* 182*0Sstevel@tonic-gate * do we need to search anything at all? (is fildes a char special tty 183*0Sstevel@tonic-gate * file?) 184*0Sstevel@tonic-gate */ 185*0Sstevel@tonic-gate if (fstat64(f, &fsb) < 0) { 186*0Sstevel@tonic-gate errno = EBADF; 187*0Sstevel@tonic-gate return (0); 188*0Sstevel@tonic-gate } 189*0Sstevel@tonic-gate if ((isatty(f) == 0) || 190*0Sstevel@tonic-gate ((fsb.st_mode & S_IFMT) != S_IFCHR)) { 191*0Sstevel@tonic-gate errno = ENOTTY; 192*0Sstevel@tonic-gate return (0); 193*0Sstevel@tonic-gate } 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate if (buflen < MAX_DEV_PATH) { 196*0Sstevel@tonic-gate errno = ERANGE; 197*0Sstevel@tonic-gate return (0); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate return (_ttyname_common(&fsb, buffer, MATCH_ALL)); 201*0Sstevel@tonic-gate } 202*0Sstevel@tonic-gate 203*0Sstevel@tonic-gate static char * 204*0Sstevel@tonic-gate _ttyname_common(struct stat64 *fsp, char *buffer, uint_t match_mask) 205*0Sstevel@tonic-gate { 206*0Sstevel@tonic-gate struct stat64 tfsb; 207*0Sstevel@tonic-gate const entry_t *srch_dirs; /* priority directories */ 208*0Sstevel@tonic-gate spcl_t *spclp; 209*0Sstevel@tonic-gate int i; 210*0Sstevel@tonic-gate int found = 0; 211*0Sstevel@tonic-gate int dirno = 0; 212*0Sstevel@tonic-gate int is_pts = 0; 213*0Sstevel@tonic-gate char *retval = NULL; 214*0Sstevel@tonic-gate char *pt = NULL; 215*0Sstevel@tonic-gate 216*0Sstevel@tonic-gate /* 217*0Sstevel@tonic-gate * We can't use lmutex_lock() here because we call malloc()/free() 218*0Sstevel@tonic-gate * and _libc_gettext(). Use the brute-force fork_lock_enter(). 219*0Sstevel@tonic-gate */ 220*0Sstevel@tonic-gate (void) fork_lock_enter(NULL); 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate /* 223*0Sstevel@tonic-gate * match special cases 224*0Sstevel@tonic-gate */ 225*0Sstevel@tonic-gate 226*0Sstevel@tonic-gate for (spclp = special_case, i = 0; i < NUMSPECIAL; spclp++, i++) { 227*0Sstevel@tonic-gate if ((spclp->spcl_inum | spclp->spcl_fsdev | 228*0Sstevel@tonic-gate spclp->spcl_rdev) == 0) { 229*0Sstevel@tonic-gate if (stat64(spclp->spcl_name, &tfsb) != 0) 230*0Sstevel@tonic-gate continue; 231*0Sstevel@tonic-gate spclp->spcl_rdev = tfsb.st_rdev; 232*0Sstevel@tonic-gate spclp->spcl_fsdev = tfsb.st_dev; 233*0Sstevel@tonic-gate spclp->spcl_inum = tfsb.st_ino; 234*0Sstevel@tonic-gate } 235*0Sstevel@tonic-gate if (match_mask == MATCH_MM) { 236*0Sstevel@tonic-gate if (spclp->spcl_rdev == fsp->st_rdev) { 237*0Sstevel@tonic-gate retval = strcpy(rbuf, spclp->spcl_name); 238*0Sstevel@tonic-gate goto out; 239*0Sstevel@tonic-gate } 240*0Sstevel@tonic-gate } else if (spclp->spcl_fsdev == fsp->st_dev && 241*0Sstevel@tonic-gate spclp->spcl_rdev == fsp->st_rdev && 242*0Sstevel@tonic-gate spclp->spcl_inum == fsp->st_ino) { 243*0Sstevel@tonic-gate retval = strcpy(rbuf, spclp->spcl_name); 244*0Sstevel@tonic-gate goto out; 245*0Sstevel@tonic-gate } 246*0Sstevel@tonic-gate } 247*0Sstevel@tonic-gate /* 248*0Sstevel@tonic-gate * additional special case: ptm clone device 249*0Sstevel@tonic-gate * ptm devs have no entries in /dev 250*0Sstevel@tonic-gate * if major number matches, just short circuit any further lookup 251*0Sstevel@tonic-gate * NOTE: the minor number of /dev/ptmx is the ptm major number 252*0Sstevel@tonic-gate */ 253*0Sstevel@tonic-gate spclp = &ptmspecial; 254*0Sstevel@tonic-gate if ((spclp->spcl_inum | spclp->spcl_fsdev | spclp->spcl_rdev) == 0) { 255*0Sstevel@tonic-gate if (stat64(spclp->spcl_name, &tfsb) == 0) { 256*0Sstevel@tonic-gate spclp->spcl_rdev = tfsb.st_rdev; 257*0Sstevel@tonic-gate spclp->spcl_fsdev = tfsb.st_dev; 258*0Sstevel@tonic-gate spclp->spcl_inum = tfsb.st_ino; 259*0Sstevel@tonic-gate } 260*0Sstevel@tonic-gate } 261*0Sstevel@tonic-gate if ((spclp->spcl_rdev != 0) && 262*0Sstevel@tonic-gate (minor(spclp->spcl_rdev) == major(fsp->st_rdev))) 263*0Sstevel@tonic-gate goto out; 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* 266*0Sstevel@tonic-gate * additional special case: pty dev 267*0Sstevel@tonic-gate * one of the known default pairs of /dev/ptyXX or /dev/ttyXX 268*0Sstevel@tonic-gate */ 269*0Sstevel@tonic-gate if ((retval = ispty(fsp, match_mask)) != NULL) 270*0Sstevel@tonic-gate goto out; 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate /* 273*0Sstevel@tonic-gate * search the priority directories 274*0Sstevel@tonic-gate */ 275*0Sstevel@tonic-gate 276*0Sstevel@tonic-gate 277*0Sstevel@tonic-gate srch_dirs = get_pri_dirs(); 278*0Sstevel@tonic-gate dev_flag = 0; 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gate while ((!found) && (srch_dirs[dirno].name != NULL)) { 281*0Sstevel@tonic-gate 282*0Sstevel@tonic-gate /* 283*0Sstevel@tonic-gate * if /dev is one of the priority directories, only 284*0Sstevel@tonic-gate * search its top level(set depth = MAX_SEARCH_DEPTH) 285*0Sstevel@tonic-gate */ 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* 288*0Sstevel@tonic-gate * Is /dev/pts then just do a quick check. We don't have 289*0Sstevel@tonic-gate * to stat the entire /dev/pts dir. 290*0Sstevel@tonic-gate */ 291*0Sstevel@tonic-gate if (strcmp(PTS, srch_dirs[dirno].name) == NULL) { 292*0Sstevel@tonic-gate if ((pt = ispts(fsp, match_mask)) != NULL) { 293*0Sstevel@tonic-gate is_pts = 1; 294*0Sstevel@tonic-gate found = 1; 295*0Sstevel@tonic-gate } 296*0Sstevel@tonic-gate } else { 297*0Sstevel@tonic-gate found = srch_dir(srch_dirs[dirno], match_mask, 298*0Sstevel@tonic-gate ((strcmp(srch_dirs[dirno].name, 299*0Sstevel@tonic-gate dev_dir.name) == 0) ? 300*0Sstevel@tonic-gate MAX_SRCH_DEPTH : 1), 0, fsp); 301*0Sstevel@tonic-gate } 302*0Sstevel@tonic-gate dirno++; 303*0Sstevel@tonic-gate } 304*0Sstevel@tonic-gate 305*0Sstevel@tonic-gate /* 306*0Sstevel@tonic-gate * search the /dev/ directory, skipping priority directories 307*0Sstevel@tonic-gate */ 308*0Sstevel@tonic-gate if (!found) 309*0Sstevel@tonic-gate found = srch_dir(dev_dir, match_mask, 0, srch_dirs, fsp); 310*0Sstevel@tonic-gate 311*0Sstevel@tonic-gate 312*0Sstevel@tonic-gate /* 313*0Sstevel@tonic-gate * return 314*0Sstevel@tonic-gate */ 315*0Sstevel@tonic-gate 316*0Sstevel@tonic-gate if (found) { 317*0Sstevel@tonic-gate if (is_pts) 318*0Sstevel@tonic-gate retval = pt; 319*0Sstevel@tonic-gate else 320*0Sstevel@tonic-gate retval = rbuf; 321*0Sstevel@tonic-gate } else if (dev_flag) 322*0Sstevel@tonic-gate retval = dev_rbuf; 323*0Sstevel@tonic-gate else 324*0Sstevel@tonic-gate retval = NULL; 325*0Sstevel@tonic-gate out: retval = (retval ? strcpy(buffer, retval) : NULL); 326*0Sstevel@tonic-gate fork_lock_exit(); 327*0Sstevel@tonic-gate return (retval); 328*0Sstevel@tonic-gate } 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate /* 331*0Sstevel@tonic-gate * POSIX.1c standard version of the function ttyname_r. 332*0Sstevel@tonic-gate * User gets it via static ttyname_r from the header file. 333*0Sstevel@tonic-gate */ 334*0Sstevel@tonic-gate int 335*0Sstevel@tonic-gate __posix_ttyname_r(int fildes, char *name, size_t namesize) 336*0Sstevel@tonic-gate { 337*0Sstevel@tonic-gate int nerrno = 0; 338*0Sstevel@tonic-gate int oerrno = errno; 339*0Sstevel@tonic-gate int namelen; 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gate errno = 0; 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate if (namesize > INT_MAX) 344*0Sstevel@tonic-gate namelen = INT_MAX; 345*0Sstevel@tonic-gate else 346*0Sstevel@tonic-gate namelen = (int)namesize; 347*0Sstevel@tonic-gate 348*0Sstevel@tonic-gate if (_ttyname_r(fildes, name, namelen) == NULL) { 349*0Sstevel@tonic-gate if (errno == 0) 350*0Sstevel@tonic-gate nerrno = EINVAL; 351*0Sstevel@tonic-gate else 352*0Sstevel@tonic-gate nerrno = errno; 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate errno = oerrno; 355*0Sstevel@tonic-gate return (nerrno); 356*0Sstevel@tonic-gate } 357*0Sstevel@tonic-gate 358*0Sstevel@tonic-gate /* 359*0Sstevel@tonic-gate * Checks if the name is under /dev/pts directory 360*0Sstevel@tonic-gate */ 361*0Sstevel@tonic-gate static char * 362*0Sstevel@tonic-gate ispts(struct stat64 *fsb, int match_mask) 363*0Sstevel@tonic-gate { 364*0Sstevel@tonic-gate static char buf[MAX_DEV_PATH]; 365*0Sstevel@tonic-gate struct stat64 stb; 366*0Sstevel@tonic-gate 367*0Sstevel@tonic-gate (void) strcpy(buf, "/dev/pts/"); 368*0Sstevel@tonic-gate itoa(minor(fsb->st_rdev), buf+strlen(buf)); 369*0Sstevel@tonic-gate 370*0Sstevel@tonic-gate if (stat64(buf, &stb) != 0) 371*0Sstevel@tonic-gate return (NULL); 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate if (match_mask == MATCH_MM) { 374*0Sstevel@tonic-gate if (stb.st_rdev == fsb->st_rdev) 375*0Sstevel@tonic-gate return (buf); 376*0Sstevel@tonic-gate } else if (stb.st_rdev == fsb->st_rdev && 377*0Sstevel@tonic-gate stb.st_dev == fsb->st_dev && 378*0Sstevel@tonic-gate stb.st_ino == fsb->st_ino) 379*0Sstevel@tonic-gate return (buf); 380*0Sstevel@tonic-gate 381*0Sstevel@tonic-gate return (NULL); 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate /* 385*0Sstevel@tonic-gate * Checks if the dev is a known pty master or slave device 386*0Sstevel@tonic-gate */ 387*0Sstevel@tonic-gate #define MAXDEFAULTPTY 48 388*0Sstevel@tonic-gate 389*0Sstevel@tonic-gate static char * 390*0Sstevel@tonic-gate ispty(struct stat64 *fsb, int match_mask) 391*0Sstevel@tonic-gate { 392*0Sstevel@tonic-gate static char buf[16]; /* big enough for "/dev/XtyXX" */ 393*0Sstevel@tonic-gate struct stat64 stb; 394*0Sstevel@tonic-gate minor_t dmin; 395*0Sstevel@tonic-gate char prefix; 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate if (ptsldev == NODEV && stat64("/dev/ttyp0", &stb) == 0) 398*0Sstevel@tonic-gate ptsldev = stb.st_rdev; 399*0Sstevel@tonic-gate 400*0Sstevel@tonic-gate /* 401*0Sstevel@tonic-gate * check for a ptsl dev (/dev/ttyXX) 402*0Sstevel@tonic-gate */ 403*0Sstevel@tonic-gate prefix = 't'; 404*0Sstevel@tonic-gate if (major(fsb->st_rdev) != major(ptsldev)) { 405*0Sstevel@tonic-gate /* 406*0Sstevel@tonic-gate * not a ptsl, check for a ptc 407*0Sstevel@tonic-gate */ 408*0Sstevel@tonic-gate if (ptcdev == NODEV && stat64("/dev/ptyp0", &stb) == 0) 409*0Sstevel@tonic-gate ptcdev = stb.st_rdev; 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate /* 412*0Sstevel@tonic-gate * check for a ptc dev (/dev/ptyXX) 413*0Sstevel@tonic-gate */ 414*0Sstevel@tonic-gate prefix = 'p'; 415*0Sstevel@tonic-gate if (major(fsb->st_rdev) != major(ptcdev)) 416*0Sstevel@tonic-gate return (NULL); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * check if minor number is in the known range 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate dmin = minor(fsb->st_rdev); 423*0Sstevel@tonic-gate if (dmin > MAXDEFAULTPTY) 424*0Sstevel@tonic-gate return (NULL); 425*0Sstevel@tonic-gate 426*0Sstevel@tonic-gate /* 427*0Sstevel@tonic-gate * modify name based on minor number 428*0Sstevel@tonic-gate */ 429*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), "/dev/%cty%c%c", 430*0Sstevel@tonic-gate prefix, 'p' + dmin / 16, "0123456789abcdef"[dmin % 16]); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate if (stat64(buf, &stb) != 0) 433*0Sstevel@tonic-gate return (NULL); 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate if (match_mask == MATCH_MM) { 436*0Sstevel@tonic-gate if (stb.st_rdev == fsb->st_rdev) 437*0Sstevel@tonic-gate return (buf); 438*0Sstevel@tonic-gate } else if (stb.st_rdev == fsb->st_rdev && 439*0Sstevel@tonic-gate stb.st_dev == fsb->st_dev && 440*0Sstevel@tonic-gate stb.st_ino == fsb->st_ino) 441*0Sstevel@tonic-gate return (buf); 442*0Sstevel@tonic-gate 443*0Sstevel@tonic-gate return (NULL); 444*0Sstevel@tonic-gate } 445*0Sstevel@tonic-gate 446*0Sstevel@tonic-gate 447*0Sstevel@tonic-gate /* 448*0Sstevel@tonic-gate * Converts a number to a string (null terminated). 449*0Sstevel@tonic-gate */ 450*0Sstevel@tonic-gate static void 451*0Sstevel@tonic-gate itoa(int i, char *ptr) 452*0Sstevel@tonic-gate { 453*0Sstevel@tonic-gate int dig = 0; 454*0Sstevel@tonic-gate int tempi; 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate tempi = i; 457*0Sstevel@tonic-gate do { 458*0Sstevel@tonic-gate dig++; 459*0Sstevel@tonic-gate tempi /= 10; 460*0Sstevel@tonic-gate } while (tempi); 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate ptr += dig; 463*0Sstevel@tonic-gate *ptr = '\0'; 464*0Sstevel@tonic-gate while (--dig >= 0) { 465*0Sstevel@tonic-gate *(--ptr) = i % 10 + '0'; 466*0Sstevel@tonic-gate i /= 10; 467*0Sstevel@tonic-gate } 468*0Sstevel@tonic-gate } 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate /* 471*0Sstevel@tonic-gate * srch_dir() searches directory path and all directories under it up 472*0Sstevel@tonic-gate * to depth directories deep for a file described by a stat structure 473*0Sstevel@tonic-gate * fsb. It puts the answer into rbuf. If a match is found on device 474*0Sstevel@tonic-gate * number only, the file name is put into dev_rbuf and dev_flag is set. 475*0Sstevel@tonic-gate * 476*0Sstevel@tonic-gate * srch_dir() returns 1 if a match (on device and inode) is found, 477*0Sstevel@tonic-gate * or 0 otherwise. 478*0Sstevel@tonic-gate * 479*0Sstevel@tonic-gate */ 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate static int 482*0Sstevel@tonic-gate srch_dir(const entry_t path, /* current path */ 483*0Sstevel@tonic-gate int match_mask, /* flags mask */ 484*0Sstevel@tonic-gate int depth, /* current depth (/dev = 0) */ 485*0Sstevel@tonic-gate const entry_t skip_dirs[], /* directories not needing searching */ 486*0Sstevel@tonic-gate struct stat64 *fsb) /* the file being searched for */ 487*0Sstevel@tonic-gate { 488*0Sstevel@tonic-gate DIR *dirp; 489*0Sstevel@tonic-gate struct dirent64 *direntp; 490*0Sstevel@tonic-gate struct stat64 tsb; 491*0Sstevel@tonic-gate char file_name[MAX_DEV_PATH]; 492*0Sstevel@tonic-gate entry_t file; 493*0Sstevel@tonic-gate char *last_comp; 494*0Sstevel@tonic-gate int found = 0; 495*0Sstevel@tonic-gate int dirno = 0; 496*0Sstevel@tonic-gate size_t path_len; 497*0Sstevel@tonic-gate 498*0Sstevel@tonic-gate file.name = file_name; 499*0Sstevel@tonic-gate file.flags = path.flags & match_mask; 500*0Sstevel@tonic-gate if (file.flags == 0) 501*0Sstevel@tonic-gate file.flags = match_mask; 502*0Sstevel@tonic-gate 503*0Sstevel@tonic-gate /* 504*0Sstevel@tonic-gate * do we need to search this directory? (always search /dev at depth 0) 505*0Sstevel@tonic-gate */ 506*0Sstevel@tonic-gate if ((skip_dirs != NULL) && (depth != 0)) 507*0Sstevel@tonic-gate while (skip_dirs[dirno].name != NULL) 508*0Sstevel@tonic-gate if (strcmp(skip_dirs[dirno++].name, path.name) == 0) 509*0Sstevel@tonic-gate return (0); 510*0Sstevel@tonic-gate 511*0Sstevel@tonic-gate /* 512*0Sstevel@tonic-gate * open directory 513*0Sstevel@tonic-gate */ 514*0Sstevel@tonic-gate if ((dirp = opendir(path.name)) == NULL) { 515*0Sstevel@tonic-gate return (0); 516*0Sstevel@tonic-gate } 517*0Sstevel@tonic-gate 518*0Sstevel@tonic-gate /* 519*0Sstevel@tonic-gate * skip two first entries ('.' and '..') 520*0Sstevel@tonic-gate */ 521*0Sstevel@tonic-gate if (((direntp = readdir64(dirp)) == NULL) || 522*0Sstevel@tonic-gate ((direntp = readdir64(dirp)) == NULL)) { 523*0Sstevel@tonic-gate (void) closedir(dirp); 524*0Sstevel@tonic-gate return (0); 525*0Sstevel@tonic-gate } 526*0Sstevel@tonic-gate 527*0Sstevel@tonic-gate path_len = strlen(path.name); 528*0Sstevel@tonic-gate (void) strcpy(file_name, path.name); 529*0Sstevel@tonic-gate last_comp = file_name + path_len; 530*0Sstevel@tonic-gate *last_comp++ = '/'; 531*0Sstevel@tonic-gate 532*0Sstevel@tonic-gate /* 533*0Sstevel@tonic-gate * read thru the directory 534*0Sstevel@tonic-gate */ 535*0Sstevel@tonic-gate while ((!found) && ((direntp = readdir64(dirp)) != NULL)) { 536*0Sstevel@tonic-gate 537*0Sstevel@tonic-gate /* 538*0Sstevel@tonic-gate * if the file name (path + "/" + d_name + NULL) would be too 539*0Sstevel@tonic-gate * long, skip it 540*0Sstevel@tonic-gate */ 541*0Sstevel@tonic-gate if ((path_len + strlen(direntp->d_name) + 2) > MAX_DEV_PATH) 542*0Sstevel@tonic-gate continue; 543*0Sstevel@tonic-gate else 544*0Sstevel@tonic-gate (void) strcpy(last_comp, direntp->d_name); 545*0Sstevel@tonic-gate 546*0Sstevel@tonic-gate if (stat64(file_name, &tsb) < 0) 547*0Sstevel@tonic-gate continue; 548*0Sstevel@tonic-gate 549*0Sstevel@tonic-gate /* 550*0Sstevel@tonic-gate * if a file is a directory and we are not too deep, recurse 551*0Sstevel@tonic-gate */ 552*0Sstevel@tonic-gate if ((tsb.st_mode & S_IFMT) == S_IFDIR) 553*0Sstevel@tonic-gate if (depth < MAX_SRCH_DEPTH) 554*0Sstevel@tonic-gate found = srch_dir(file, match_mask, depth+1, 555*0Sstevel@tonic-gate skip_dirs, fsb); 556*0Sstevel@tonic-gate else 557*0Sstevel@tonic-gate continue; 558*0Sstevel@tonic-gate 559*0Sstevel@tonic-gate /* 560*0Sstevel@tonic-gate * else if it is not a directory, is it a character special 561*0Sstevel@tonic-gate * file? 562*0Sstevel@tonic-gate */ 563*0Sstevel@tonic-gate else if ((tsb.st_mode & S_IFMT) == S_IFCHR) { 564*0Sstevel@tonic-gate int flag = 0; 565*0Sstevel@tonic-gate if (tsb.st_dev == fsb->st_dev) 566*0Sstevel@tonic-gate flag |= MATCH_FS; 567*0Sstevel@tonic-gate if (tsb.st_rdev == fsb->st_rdev) 568*0Sstevel@tonic-gate flag |= MATCH_MM; 569*0Sstevel@tonic-gate if (tsb.st_ino == fsb->st_ino) 570*0Sstevel@tonic-gate flag |= MATCH_INO; 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate if ((flag & file.flags) == file.flags) { 573*0Sstevel@tonic-gate (void) strcpy(rbuf, file.name); 574*0Sstevel@tonic-gate found = 1; 575*0Sstevel@tonic-gate } else if ((flag & (MATCH_MM | MATCH_FS)) == 576*0Sstevel@tonic-gate (MATCH_MM | MATCH_FS)) { 577*0Sstevel@tonic-gate 578*0Sstevel@tonic-gate /* 579*0Sstevel@tonic-gate * no (inodes do not match), but save the name 580*0Sstevel@tonic-gate * for later 581*0Sstevel@tonic-gate */ 582*0Sstevel@tonic-gate (void) strcpy(dev_rbuf, file.name); 583*0Sstevel@tonic-gate dev_flag = 1; 584*0Sstevel@tonic-gate } 585*0Sstevel@tonic-gate } 586*0Sstevel@tonic-gate } 587*0Sstevel@tonic-gate (void) closedir(dirp); 588*0Sstevel@tonic-gate return (found); 589*0Sstevel@tonic-gate } 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate 592*0Sstevel@tonic-gate /* 593*0Sstevel@tonic-gate * get_pri_dirs() - returns a pointer to an array of strings, where each string 594*0Sstevel@tonic-gate * is a priority directory name. The end of the array is marked by a NULL 595*0Sstevel@tonic-gate * pointer. The priority directories' names are obtained from the file 596*0Sstevel@tonic-gate * /etc/ttysrch if it exists and is readable, or if not, a default hard-coded 597*0Sstevel@tonic-gate * list of directories. 598*0Sstevel@tonic-gate * 599*0Sstevel@tonic-gate * /etc/ttysrch, if used, is read in as a string of characters into memory and 600*0Sstevel@tonic-gate * then parsed into strings of priority directory names, omitting comments and 601*0Sstevel@tonic-gate * blank lines. 602*0Sstevel@tonic-gate * 603*0Sstevel@tonic-gate */ 604*0Sstevel@tonic-gate 605*0Sstevel@tonic-gate #define START_STATE 1 606*0Sstevel@tonic-gate #define COMMENT_STATE 2 607*0Sstevel@tonic-gate #define DIRNAME_STATE 3 608*0Sstevel@tonic-gate #define FLAG_STATE 4 609*0Sstevel@tonic-gate #define CHECK_STATE 5 610*0Sstevel@tonic-gate 611*0Sstevel@tonic-gate #define COMMENT_CHAR '#' 612*0Sstevel@tonic-gate #define EOLN_CHAR '\n' 613*0Sstevel@tonic-gate 614*0Sstevel@tonic-gate static const entry_t * 615*0Sstevel@tonic-gate get_pri_dirs(void) 616*0Sstevel@tonic-gate { 617*0Sstevel@tonic-gate int fd, state; 618*0Sstevel@tonic-gate size_t sz; 619*0Sstevel@tonic-gate ssize_t size; 620*0Sstevel@tonic-gate struct stat64 sb; 621*0Sstevel@tonic-gate char *buf, *ebuf; 622*0Sstevel@tonic-gate entry_t *vec; 623*0Sstevel@tonic-gate 624*0Sstevel@tonic-gate /* 625*0Sstevel@tonic-gate * if no /etc/ttysrch, use defaults 626*0Sstevel@tonic-gate */ 627*0Sstevel@tonic-gate if ((fd = open(TTYSRCH, 0)) < 0) 628*0Sstevel@tonic-gate return (def_srch_dirs); 629*0Sstevel@tonic-gate 630*0Sstevel@tonic-gate if (fstat64(fd, &sb) < 0) { 631*0Sstevel@tonic-gate (void) close(fd); 632*0Sstevel@tonic-gate return (def_srch_dirs); 633*0Sstevel@tonic-gate } 634*0Sstevel@tonic-gate 635*0Sstevel@tonic-gate sz = (size_t)sb.st_size; 636*0Sstevel@tonic-gate if (dir_vec != NULL && sz == dir_size && 637*0Sstevel@tonic-gate sb.st_mtim.tv_sec == dir_mtim.tv_sec && 638*0Sstevel@tonic-gate sb.st_mtim.tv_nsec == dir_mtim.tv_nsec) { 639*0Sstevel@tonic-gate /* 640*0Sstevel@tonic-gate * size & modification time match 641*0Sstevel@tonic-gate * no need to reread TTYSRCH 642*0Sstevel@tonic-gate * just return old pointer 643*0Sstevel@tonic-gate */ 644*0Sstevel@tonic-gate (void) close(fd); 645*0Sstevel@tonic-gate return (dir_vec); 646*0Sstevel@tonic-gate } 647*0Sstevel@tonic-gate buf = realloc(dir_buf, sz + 1); 648*0Sstevel@tonic-gate if (buf != NULL) { 649*0Sstevel@tonic-gate dir_buf = buf; 650*0Sstevel@tonic-gate size = read(fd, dir_buf, sz); 651*0Sstevel@tonic-gate } 652*0Sstevel@tonic-gate (void) close(fd); 653*0Sstevel@tonic-gate 654*0Sstevel@tonic-gate if (buf == NULL || size < 0) { 655*0Sstevel@tonic-gate if (dir_vec != NULL) { 656*0Sstevel@tonic-gate free(dir_vec); 657*0Sstevel@tonic-gate dir_vec = NULL; 658*0Sstevel@tonic-gate } 659*0Sstevel@tonic-gate return ((entry_t *)def_srch_dirs); 660*0Sstevel@tonic-gate } 661*0Sstevel@tonic-gate dir_size = sz; 662*0Sstevel@tonic-gate dir_mtim = sb.st_mtim; 663*0Sstevel@tonic-gate 664*0Sstevel@tonic-gate /* 665*0Sstevel@tonic-gate * ensure newline termination for buffer. Add an extra 666*0Sstevel@tonic-gate * entry to dir_vec for null terminator 667*0Sstevel@tonic-gate */ 668*0Sstevel@tonic-gate ebuf = &dir_buf[size]; 669*0Sstevel@tonic-gate *ebuf++ = '\n'; 670*0Sstevel@tonic-gate for (sz = 1, buf = dir_buf; buf < ebuf; ++buf) 671*0Sstevel@tonic-gate if (*buf == '\n') 672*0Sstevel@tonic-gate ++sz; 673*0Sstevel@tonic-gate 674*0Sstevel@tonic-gate sz *= sizeof (*dir_vec); 675*0Sstevel@tonic-gate vec = realloc(dir_vec, sz); 676*0Sstevel@tonic-gate if (vec == NULL) { 677*0Sstevel@tonic-gate if (dir_vec != NULL) { 678*0Sstevel@tonic-gate free(dir_vec); 679*0Sstevel@tonic-gate dir_vec = NULL; 680*0Sstevel@tonic-gate } 681*0Sstevel@tonic-gate return (def_srch_dirs); 682*0Sstevel@tonic-gate } 683*0Sstevel@tonic-gate dir_vec = vec; 684*0Sstevel@tonic-gate state = START_STATE; 685*0Sstevel@tonic-gate for (buf = dir_buf; buf < ebuf; ++buf) { 686*0Sstevel@tonic-gate switch (state) { 687*0Sstevel@tonic-gate 688*0Sstevel@tonic-gate case START_STATE: 689*0Sstevel@tonic-gate if (*buf == COMMENT_CHAR) { 690*0Sstevel@tonic-gate state = COMMENT_STATE; 691*0Sstevel@tonic-gate break; 692*0Sstevel@tonic-gate } 693*0Sstevel@tonic-gate if (!isspace(*buf)) /* skip leading white space */ 694*0Sstevel@tonic-gate state = DIRNAME_STATE; 695*0Sstevel@tonic-gate vec->name = buf; 696*0Sstevel@tonic-gate vec->flags = 0; 697*0Sstevel@tonic-gate break; 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate case COMMENT_STATE: 700*0Sstevel@tonic-gate if (*buf == EOLN_CHAR) 701*0Sstevel@tonic-gate state = START_STATE; 702*0Sstevel@tonic-gate break; 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate case DIRNAME_STATE: 705*0Sstevel@tonic-gate if (*buf == EOLN_CHAR) { 706*0Sstevel@tonic-gate state = CHECK_STATE; 707*0Sstevel@tonic-gate *buf = '\0'; 708*0Sstevel@tonic-gate } else if (isspace(*buf)) { 709*0Sstevel@tonic-gate /* skip trailing white space */ 710*0Sstevel@tonic-gate state = FLAG_STATE; 711*0Sstevel@tonic-gate *buf = '\0'; 712*0Sstevel@tonic-gate } 713*0Sstevel@tonic-gate break; 714*0Sstevel@tonic-gate 715*0Sstevel@tonic-gate case FLAG_STATE: 716*0Sstevel@tonic-gate switch (*buf) { 717*0Sstevel@tonic-gate case 'M': 718*0Sstevel@tonic-gate vec->flags |= MATCH_MM; 719*0Sstevel@tonic-gate break; 720*0Sstevel@tonic-gate case 'F': 721*0Sstevel@tonic-gate vec->flags |= MATCH_FS; 722*0Sstevel@tonic-gate break; 723*0Sstevel@tonic-gate case 'I': 724*0Sstevel@tonic-gate vec->flags |= MATCH_INO; 725*0Sstevel@tonic-gate break; 726*0Sstevel@tonic-gate case EOLN_CHAR: 727*0Sstevel@tonic-gate state = CHECK_STATE; 728*0Sstevel@tonic-gate break; 729*0Sstevel@tonic-gate } 730*0Sstevel@tonic-gate break; 731*0Sstevel@tonic-gate 732*0Sstevel@tonic-gate case CHECK_STATE: 733*0Sstevel@tonic-gate if (strncmp(vec->name, DEV, strlen(DEV)) != 0) { 734*0Sstevel@tonic-gate int tfd = open("/dev/console", O_WRONLY); 735*0Sstevel@tonic-gate if (tfd >= 0) { 736*0Sstevel@tonic-gate char buf[256]; 737*0Sstevel@tonic-gate /* LINTED variable format specifier */ 738*0Sstevel@tonic-gate (void) snprintf(buf, sizeof (buf), 739*0Sstevel@tonic-gate _libc_gettext( 740*0Sstevel@tonic-gate "ERROR: Entry '%s' in /etc/ttysrch ignored.\n"), 741*0Sstevel@tonic-gate vec->name); 742*0Sstevel@tonic-gate (void) write(tfd, buf, strlen(buf)); 743*0Sstevel@tonic-gate (void) close(tfd); 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate } else { 746*0Sstevel@tonic-gate char *slash; 747*0Sstevel@tonic-gate slash = vec->name + strlen(vec->name) - 1; 748*0Sstevel@tonic-gate while (*slash == '/') 749*0Sstevel@tonic-gate *slash-- = '\0'; 750*0Sstevel@tonic-gate if (vec->flags == 0) 751*0Sstevel@tonic-gate vec->flags = MATCH_ALL; 752*0Sstevel@tonic-gate vec++; 753*0Sstevel@tonic-gate } 754*0Sstevel@tonic-gate state = START_STATE; 755*0Sstevel@tonic-gate /* 756*0Sstevel@tonic-gate * This state does not consume a character, so 757*0Sstevel@tonic-gate * reposition the pointer. 758*0Sstevel@tonic-gate */ 759*0Sstevel@tonic-gate buf--; 760*0Sstevel@tonic-gate break; 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate } 763*0Sstevel@tonic-gate } 764*0Sstevel@tonic-gate vec->name = NULL; 765*0Sstevel@tonic-gate return (dir_vec); 766*0Sstevel@tonic-gate } 767*0Sstevel@tonic-gate 768*0Sstevel@tonic-gate 769*0Sstevel@tonic-gate char * 770*0Sstevel@tonic-gate ttyname(int f) 771*0Sstevel@tonic-gate { 772*0Sstevel@tonic-gate char *ans = tsdalloc(_T_TTYNAME, MAX_DEV_PATH, NULL); 773*0Sstevel@tonic-gate 774*0Sstevel@tonic-gate if (ans == NULL) 775*0Sstevel@tonic-gate return (NULL); 776*0Sstevel@tonic-gate return (_ttyname_r(f, ans, MAX_DEV_PATH)); 777*0Sstevel@tonic-gate } 778