ttyname.c 3.4 KB

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