fdwalk should return 0 on an empty directory
[kopensolaris-gnu/glibc.git] / sysdeps / posix / ttyname_r.c
1 /* Copyright (C) 1991,92,93,95,96,97,98,2004 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 <stdlib.h>
28
29 #ifndef MIN
30 # define MIN(a, b) ((a) < (b) ? (a) : (b))
31 #endif
32
33 static const char dev[] = "/dev";
34
35 static int getttyname_r (int fd, char *buf, size_t buflen,
36                          dev_t mydev, ino_t myino, int save,
37                          int *dostat) __THROW internal_function;
38
39 static int
40 internal_function
41 getttyname_r (fd, buf, buflen, mydev, myino, save, dostat)
42      int fd;
43      char *buf;
44      size_t buflen;
45      dev_t mydev;
46      ino_t myino;
47      int save;
48      int *dostat;
49 {
50   struct stat st;
51   DIR *dirstream;
52   struct dirent *d;
53
54   dirstream = __opendir (dev);
55   if (dirstream == NULL)
56     {
57       *dostat = -1;
58       return errno;
59     }
60
61   while ((d = __readdir (dirstream)) != NULL)
62     if (((ino_t) d->d_fileno == myino || *dostat)
63         && strcmp (d->d_name, "stdin")
64         && strcmp (d->d_name, "stdout")
65         && strcmp (d->d_name, "stderr"))
66       {
67         char *cp;
68         size_t needed = _D_EXACT_NAMLEN (d) + 1;
69
70         if (needed > buflen)
71           {
72             *dostat = -1;
73             (void) __closedir (dirstream);
74             __set_errno (ERANGE);
75             return ERANGE;
76           }
77
78         cp = __stpncpy (&buf[sizeof (dev)], d->d_name, needed);
79         cp[0] = '\0';
80
81         if (stat (buf, &st) == 0
82 #ifdef _STATBUF_ST_RDEV
83             && S_ISCHR (st.st_mode) && st.st_rdev == mydev
84 #else
85             && (ino_t) d->d_fileno == myino && st.st_dev == mydev
86 #endif
87            )
88           {
89             (void) __closedir (dirstream);
90             __set_errno (save);
91             return 0;
92           }
93       }
94
95   (void) __closedir (dirstream);
96   __set_errno (save);
97   /* It is not clear what to return in this case.  `isatty' says FD
98      refers to a TTY but no entry in /dev has this inode.  */
99   return ENOTTY;
100 }
101
102 /* Store at most BUFLEN character of the pathname of the terminal FD is
103    open on in BUF.  Return 0 on success,  otherwise an error number.  */
104 int
105 __ttyname_r (fd, buf, buflen)
106      int fd;
107      char *buf;
108      size_t buflen;
109 {
110   struct stat st;
111   int dostat = 0;
112   int save = errno;
113   int ret;
114
115   /* Test for the absolute minimal size.  This makes life easier inside
116      the loop.  */
117   if (!buf)
118     {
119       __set_errno (EINVAL);
120       return EINVAL;
121     }
122
123   if (buflen < (int) (sizeof (dev) + 1))
124     {
125       __set_errno (ERANGE);
126       return ERANGE;
127     }
128
129   if (!__isatty (fd))
130     {
131       __set_errno (ENOTTY);
132       return ENOTTY;
133     }
134
135   if (fstat (fd, &st) < 0)
136     return errno;
137
138   /* Prepare the result buffer.  */
139   memcpy (buf, dev, sizeof (dev) - 1);
140   buf[sizeof (dev) - 1] = '/';
141   buflen -= sizeof (dev);
142
143 #ifdef _STATBUF_ST_RDEV
144   ret = getttyname_r (fd, buf, buflen, st.st_rdev, st.st_ino, save,
145                       &dostat);
146 #else
147   ret = getttyname_r (fd, buf, buflen, st.st_dev, st.st_ino, save,
148                       &dostat);
149 #endif
150
151   if (ret && dostat != -1)
152     {
153       dostat = 1;
154 #ifdef _STATBUF_ST_RDEV
155       ret = getttyname_r (fd, buf, buflen, st.st_rdev, st.st_ino,
156                           save, &dostat);
157 #else
158       ret = getttyname_r (fd, buf, buflen, st.st_dev, st.st_ino,
159                           save, &dostat);
160 #endif
161     }
162
163   return ret;
164 }
165
166 weak_alias (__ttyname_r, ttyname_r)