malloc: add glibc compat symbols
[uclibc-ng.git] / libc / termios / ttyname.c
blob5fcf23b6415380ee74f1a6bfbd3fd0711e843a02
1 /*
2 * Copyright (C) Jan 1, 2004 Manuel Novoa III
3 * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
5 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6 */
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.
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 */
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.)
24 * If you change this, also change _SC_TTY_NAME_MAX in libc/unistd/sysconf.c
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>
35 #define TTYNAME_BUFLEN 32
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 */
45 int ttyname_r(int fd, char *ubuf, size_t ubuflen)
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];
57 if (fstat(fd, &st) < 0) {
58 return errno;
61 rv = ENOTTY; /* Set up the default return value. */
63 if (!isatty(fd)) {
64 goto DONE;
67 for (p = dirlist ; *p ; p += 1 + p[-1]) {
68 len = *p++;
70 assert(len + 2 <= TTYNAME_BUFLEN); /* dirname + 1 char + nul */
72 strcpy(buf, p);
73 s = buf + len;
74 len = (TTYNAME_BUFLEN-2) - len; /* Available non-nul space. */
76 if (!(fp = opendir(p))) {
77 continue;
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;
87 strcpy(s, d->d_name);
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);
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;
108 goto DONE;
112 closedir(fp);
115 DONE:
116 __set_errno(rv);
118 return rv;
120 libc_hidden_def(ttyname_r)
122 char *ttyname(int fd)
124 static char name[TTYNAME_BUFLEN];
126 return ttyname_r(fd, name, TTYNAME_BUFLEN) ? NULL : name;