]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/uclibc/lib/contrib/uclibc/libc/termios/ttyname.c
Update
[l4.git] / l4 / pkg / l4re-core / uclibc / lib / contrib / uclibc / libc / termios / ttyname.c
1 /*
2  * Copyright (C) Jan 1, 2004    Manuel Novoa III
3  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4  *
5  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6  */
7
8 /*
9  * Kept the same approach, but rewrote the code for the most part.
10  * Fixed some minor issues plus (as I recall) one SUSv3 errno case.
11  */
12
13 /* This is a fairly slow approach.  We do a linear search through some
14  * directories looking for a match.  Yes this is lame.  But it should
15  * work, should be small, and will return names that match what is on
16  * disk.  Another approach we could use would be to use the info in
17  * /proc/self/fd, but that is even more lame since it requires /proc */
18
19 /* SUSv3 mandates TTY_NAME_MAX as 9.  This is obviously insufficient.
20  * However, there is no need to waste space and support non-standard
21  * tty names either.  So we compromise and use the following buffer
22  * length.  (Erik and Manuel agreed that 32 was more than reasonable.)
23  *
24  * If you change this, also change _SC_TTY_NAME_MAX in libc/unistd/sysconf.c
25  */
26
27 #include <string.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <unistd.h>
31 #include <dirent.h>
32 #include <sys/stat.h>
33
34
35 #define TTYNAME_BUFLEN          32
36
37 static const char dirlist[] =
38 /*   12345670123 */
39 "\010/dev/vc/\0"        /* Try /dev/vc first (be devfs compatible) */
40 "\011/dev/tts/\0"       /* and /dev/tts next (be devfs compatible) */
41 "\011/dev/pty/\0"       /* and /dev/pty next (be devfs compatible) */
42 "\011/dev/pts/\0"       /* and try /dev/pts next */
43 "\005/dev/\0";          /* and try walking through /dev last */
44
45 int ttyname_r(int fd, char *ubuf, size_t ubuflen)
46 {
47         struct dirent *d;
48         struct stat st;
49         struct stat dst;
50         const char *p;
51         char *s;
52         DIR *fp;
53         int rv;
54         size_t len;
55         char buf[TTYNAME_BUFLEN];
56
57         if (fstat(fd, &st) < 0) {
58                 return errno;
59         }
60
61         rv = ENOTTY;                            /* Set up the default return value. */
62
63         if (!isatty(fd)) {
64                 goto DONE;
65         }
66
67         for (p = dirlist ; *p ; p += 1 + p[-1]) {
68                 len = *p++;
69
70                 assert(len + 2 <= TTYNAME_BUFLEN); /* dirname + 1 char + nul */
71
72                 strcpy(buf, p);
73                 s = buf + len;
74                 len =  (TTYNAME_BUFLEN-2) - len; /* Available non-nul space. */
75
76                 if (!(fp = opendir(p))) {
77                         continue;
78                 }
79
80                 while ((d = readdir(fp)) != NULL) {
81                         /* This should never trigger for standard names, but we
82                          * check it to be safe.  */
83                         if (strlen(d->d_name) > len) { /* Too big? */
84                                 continue;
85                         }
86
87                         strcpy(s, d->d_name);
88
89                         if ((lstat(buf, &dst) == 0)
90 #if 0
91                                 /* Stupid filesystems like cramfs fail to guarantee that
92                                  * st_ino and st_dev uniquely identify a file, contrary to
93                                  * SuSv3, so we cannot be quite so precise as to require an
94                                  * exact match.  Settle for something less...  Grumble... */
95                                 && (st.st_dev == dst.st_dev) && (st.st_ino == dst.st_ino)
96 #else
97                                 && S_ISCHR(dst.st_mode) && (st.st_rdev == dst.st_rdev)
98 #endif
99                                 ) {                             /* Found it! */
100                                 closedir(fp);
101
102                                 /* We treat NULL buf as ERANGE rather than EINVAL. */
103                                 rv = ERANGE;
104                                 if (ubuf && (strlen(buf) <= ubuflen)) {
105                                         strcpy(ubuf, buf);
106                                         rv = 0;
107                                 }
108                                 goto DONE;
109                         }
110                 }
111
112                 closedir(fp);
113         }
114
115  DONE:
116         __set_errno(rv);
117
118         return rv;
119 }
120 libc_hidden_def(ttyname_r)
121
122 char *ttyname(int fd)
123 {
124         static char name[TTYNAME_BUFLEN];
125
126         return ttyname_r(fd, name, TTYNAME_BUFLEN) ? NULL : name;
127 }