source: trunk/libs/newlib/src/newlib/libc/sys/linux/ttyname_r.c

Last change on this file was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 4.6 KB
Line 
1/* Copyright (C) 1991,92,93,1995-1999,2000,2001 Free Software Foundation, Inc.
2   This file is part of the GNU C Library.
3
4   The GNU C Library is free software; you can redistribute it and/or
5   modify it under the terms of the GNU Lesser General Public
6   License as published by the Free Software Foundation; either
7   version 2.1 of the License, or (at your option) any later version.
8
9   The GNU C Library is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12   Lesser General Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public
15   License along with the GNU C Library; if not, write to the Free
16   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17   02111-1307 USA.  */
18
19#include <errno.h>
20#include <limits.h>
21#include <stddef.h>
22#include <dirent.h>
23#include <sys/types.h>
24#include <sys/stat.h>
25#include <unistd.h>
26#include <string.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <machine/weakalias.h>
30
31static int getttyname_r (char *buf, size_t buflen,
32                         dev_t mydev, ino64_t myino, int save,
33                         int *dostat);
34
35extern struct dirent64 *__readdir64 (DIR *);
36
37static int
38getttyname_r (char *buf, size_t buflen, dev_t mydev, ino64_t myino,
39              int save, int *dostat)
40{
41  struct stat64 st;
42  DIR *dirstream;
43  struct dirent64 *d;
44  size_t devlen = strlen (buf);
45
46  dirstream = opendir (buf);
47  if (dirstream == NULL)
48    {
49      *dostat = -1;
50      return errno;
51    }
52
53  while ((d = __readdir64 (dirstream)) != NULL)
54    {
55      if ((d->d_ino == myino || *dostat)
56          && strcmp (d->d_name, "stdin")
57          && strcmp (d->d_name, "stdout")
58          && strcmp (d->d_name, "stderr"))
59        {
60          size_t needed = strlen (d->d_name) + 1;
61
62          if (needed > buflen)
63            {
64              *dostat = -1;
65              (void) closedir (dirstream);
66              __set_errno (ERANGE);
67              return ERANGE;
68            }
69
70          strncpy (buf + devlen, d->d_name, needed);
71
72          if (stat64 (buf, &st) == 0
73#ifdef _STATBUF_ST_RDEV
74              && S_ISCHR (st.st_mode) && st.st_rdev == mydev
75#else
76              && d->d_ino == myino && st.st_dev == mydev
77#endif
78             )
79            {
80              (void) closedir (dirstream);
81              __set_errno (save);
82              return 0;
83            }
84        }
85    }
86
87  (void) closedir (dirstream);
88  __set_errno (save);
89  /* It is not clear what to return in this case.  `isatty' says FD
90     refers to a TTY but no entry in /dev has this inode.  */
91  return ENOTTY;
92}
93
94/* Store at most BUFLEN character of the pathname of the terminal FD is
95   open on in BUF.  Return 0 on success,  otherwise an error number.  */
96int
97__ttyname_r (int fd, char *buf, size_t buflen)
98{
99  char procname[30];
100  struct stat64 st, st1;
101  int dostat = 0;
102  int save = errno;
103  int ret;
104
105  /* Test for the absolute minimal size.  This makes life easier inside
106     the loop.  */
107  if (!buf)
108    {
109      __set_errno (EINVAL);
110      return EINVAL;
111    }
112
113  if (buflen < sizeof ("/dev/pts/"))
114    {
115      __set_errno (ERANGE);
116      return ERANGE;
117    }
118
119  if (!isatty (fd))
120    {
121      __set_errno (ENOTTY);
122      return ENOTTY;
123    }
124
125  /* We try using the /proc filesystem.  */
126  sprintf (procname, "/proc/self/fd/%d", fd);
127
128  ret = readlink (procname, buf, buflen - 1);
129  if (ret != -1 && buf[0] != '[')
130    {
131      buf[ret] = '\0';
132      return 0;
133    }
134  if (ret == -1 && errno == ENAMETOOLONG)
135    {
136      __set_errno (ERANGE);
137      return ERANGE;
138    }
139
140  if (fstat64 (fd, &st) < 0)
141    return errno;
142
143  /* Prepare the result buffer.  */
144  memcpy (buf, "/dev/pts/", sizeof ("/dev/pts/"));
145  buflen -= sizeof ("/dev/pts/") - 1;
146
147  if (stat64 (buf, &st1) == 0 && S_ISDIR (st1.st_mode))
148    {
149#ifdef _STATBUF_ST_RDEV
150      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save,
151                          &dostat);
152#else
153      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save,
154                          &dostat);
155#endif
156    }
157  else
158    {
159      __set_errno (save);
160      ret = ENOENT;
161    }
162
163  if (ret && dostat != -1)
164    {
165      buf[sizeof ("/dev/") - 1] = '\0';
166      buflen += sizeof ("pts/") - 1;
167#ifdef _STATBUF_ST_RDEV
168      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino, save,
169                          &dostat);
170#else
171      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino, save,
172                          &dostat);
173#endif
174    }
175
176  if (ret && dostat != -1)
177    {
178      buf[sizeof ("/dev/") - 1] = '\0';
179      dostat = 1;
180#ifdef _STATBUF_ST_RDEV
181      ret = getttyname_r (buf, buflen, st.st_rdev, st.st_ino,
182                          save, &dostat);
183#else
184      ret = getttyname_r (buf, buflen, st.st_dev, st.st_ino,
185                          save, &dostat);
186#endif
187    }
188
189  return ret;
190}
191
192weak_alias (__ttyname_r, ttyname_r)
Note: See TracBrowser for help on using the repository browser.