OSDN Git Service

Hide more
[uclinux-h8/uClibc.git] / libc / termios / ttyname.c
1 #include <string.h>
2 #include <errno.h>
3 #include <assert.h>
4 #include <unistd.h>
5 #include <dirent.h>
6 #include <sys/stat.h>
7
8 /* Jan 1, 2004    Manuel Novoa III
9  *
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.
12  */
13
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 */
19
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.)
24  *
25  * If you change this, also change _SC_TTY_NAME_MAX in libc/unistd/sysconf.c
26  */
27 #define TTYNAME_BUFLEN          32
28
29 static const char dirlist[] =
30 /*   12345670123 */
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 */
36
37 int attribute_hidden __ttyname_r(int fd, char *ubuf, size_t ubuflen)
38 {
39         struct dirent *d;
40         struct stat st;
41         struct stat dst;
42         const char *p;
43         char *s;
44         DIR *fp;
45         int rv;
46         int len;
47         char buf[TTYNAME_BUFLEN];
48
49         if (fstat(fd, &st) < 0) {
50                 return errno;
51         }
52
53         rv = ENOTTY;                            /* Set up the default return value. */
54
55         if (!isatty(fd)) {
56                 goto DONE;
57         }
58
59         for (p = dirlist ; *p ; p += 1 + p[-1]) {
60                 len = *p++;
61
62                 assert(len + 2 <= TTYNAME_BUFLEN); /* dirname + 1 char + nul */
63
64                 __strcpy(buf, p);
65                 s = buf + len;
66                 len =  (TTYNAME_BUFLEN-2) - len; /* Available non-nul space. */
67
68                 if (!(fp = opendir(p))) {
69                         continue;
70                 }
71
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? */
76                                 continue;
77                         }
78
79                         __strcpy(s, d->d_name);
80
81                         if ((lstat(buf, &dst) == 0)
82 #if 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)
88 #else
89                                 && S_ISCHR(dst.st_mode) && (st.st_rdev == dst.st_rdev)
90 #endif
91                                 ) {                             /* Found it! */
92                                 closedir(fp);
93
94                                 /* We treat NULL buf as ERANGE rather than EINVAL. */
95                                 rv = ERANGE;
96                                 if (ubuf && (__strlen(buf) <= ubuflen)) {
97                                         __strcpy(ubuf, buf);
98                                         rv = 0;
99                                 }
100                                 goto DONE;
101                         }
102                 }
103
104                 closedir(fp);
105         }
106
107  DONE:
108         __set_errno(rv);
109
110         return rv;
111 }
112 strong_alias(__ttyname_r,ttyname_r)
113
114 char *ttyname(int fd)
115 {
116         static char name[TTYNAME_BUFLEN];
117
118         return __ttyname_r(fd, name, TTYNAME_BUFLEN) ? NULL : name;
119 }