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