8 /* Jan 1, 2004 Manuel Novoa III
10 * Kept the same approach, but rewrote the code for the most part.
11 * Fixed some minor issues plus (as I recall) one SUSv3 errno case.
14 /* This is a fairly slow approach. We do a linear search through some
15 * directories looking for a match. Yes this is lame. But it should
16 * work, should be small, and will return names that match what is on
17 * disk. Another approach we could use would be to use the info in
18 * /proc/self/fd, but that is even more lame since it requires /proc */
20 /* SUSv3 mandates TTY_NAME_MAX as 9. This is obviously insufficient.
21 * However, there is no need to waste space and support non-standard
22 * tty names either. So we compromise and use the following buffer
23 * length. (Erik and Manuel agreed that 32 was more than reasonable.)
25 * If you change this, also change _SC_TTY_NAME_MAX in libc/unistd/sysconf.c
27 #define TTYNAME_BUFLEN 32
29 static const char dirlist[] =
31 "\010/dev/vc/\0" /* Try /dev/vc first (be devfs compatible) */
32 "\011/dev/tts/\0" /* and /dev/tts next (be devfs compatible) */
33 "\011/dev/pty/\0" /* and /dev/pty next (be devfs compatible) */
34 "\011/dev/pts/\0" /* and try /dev/pts next */
35 "\005/dev/\0"; /* and try walking through /dev last */
37 int attribute_hidden __ttyname_r(int fd, char *ubuf, size_t ubuflen)
47 char buf[TTYNAME_BUFLEN];
49 if (fstat(fd, &st) < 0) {
53 rv = ENOTTY; /* Set up the default return value. */
59 for (p = dirlist ; *p ; p += 1 + p[-1]) {
62 assert(len + 2 <= TTYNAME_BUFLEN); /* dirname + 1 char + nul */
66 len = (TTYNAME_BUFLEN-2) - len; /* Available non-nul space. */
68 if (!(fp = opendir(p))) {
72 while ((d = readdir(fp)) != NULL) {
73 /* This should never trigger for standard names, but we
74 * check it to be safe. */
75 if (__strlen(d->d_name) > len) { /* Too big? */
79 __strcpy(s, d->d_name);
81 if ((lstat(buf, &dst) == 0)
83 /* Stupid filesystems like cramfs fail to guarantee that
84 * st_ino and st_dev uniquely identify a file, contrary to
85 * SuSv3, so we cannot be quite so precise as to require an
86 * exact match. Settle for something less... Grumble... */
87 && (st.st_dev == dst.st_dev) && (st.st_ino == dst.st_ino)
89 && S_ISCHR(dst.st_mode) && (st.st_rdev == dst.st_rdev)
94 /* We treat NULL buf as ERANGE rather than EINVAL. */
96 if (ubuf && (__strlen(buf) <= ubuflen)) {
112 strong_alias(__ttyname_r,ttyname_r)
114 char *ttyname(int fd)
116 static char name[TTYNAME_BUFLEN];
118 return __ttyname_r(fd, name, TTYNAME_BUFLEN) ? NULL : name;