maint: update copyright
[gnulib.git] / tests / test-ptsname_r.c
1 /* Test of ptsname_r(3).
2    Copyright (C) 2010-2014 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program 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
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 #include <config.h>
18
19 #include <stdlib.h>
20
21 #include "signature.h"
22 SIGNATURE_CHECK (ptsname_r, int, (int, char *, size_t));
23
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <sys/stat.h>
31
32 #include "same-inode.h"
33
34 #include "macros.h"
35
36 /* Compare two slave names.
37    On some systems, there are hard links in the /dev/ directory.
38    For example, on OSF/1 5.1,
39      /dev/ttyp0 == /dev/pts/0
40      /dev/ttyp9 == /dev/pts/9
41      /dev/ttypa == /dev/pts/10
42      /dev/ttype == /dev/pts/14
43  */
44 static int
45 same_slave (const char *slave_name1, const char *slave_name2)
46 {
47   struct stat statbuf1;
48   struct stat statbuf2;
49
50   return (strcmp (slave_name1, slave_name2) == 0
51           || (stat (slave_name1, &statbuf1) >= 0
52               && stat (slave_name2, &statbuf2) >= 0
53               && SAME_INODE (statbuf1, statbuf2)));
54 }
55
56 static char *
57 null_ptr (void)
58 {
59   return NULL;
60 }
61
62 static void
63 test_errors (int fd, const char *slave)
64 {
65   char buffer[256];
66   size_t len;
67   size_t buflen_max;
68   size_t buflen;
69   int result;
70
71   len = strlen (slave);
72   buflen_max = len + 5;
73   if (buflen_max > sizeof buffer)
74     buflen_max = sizeof buffer;
75   for (buflen = 0; buflen <= buflen_max; buflen++)
76     {
77       memset (buffer, 'X', sizeof buffer);
78       errno = 0;
79       result = ptsname_r (fd, buffer, buflen);
80       if (buflen > len)
81         {
82           ASSERT (result == 0);
83           ASSERT (buffer[0] == '/');
84         }
85       else
86         {
87           ASSERT (result != 0);
88           ASSERT (result == errno);
89           ASSERT (errno == ERANGE);
90           ASSERT (buffer[0] == 'X');
91         }
92     }
93
94   errno = 0;
95   result = ptsname_r (fd, null_ptr (), 0);
96   ASSERT (result != 0);
97   ASSERT (result == errno);
98   ASSERT (errno == EINVAL);
99 }
100
101 int
102 main (void)
103 {
104 #if HAVE_DECL_ALARM
105   /* Declare failure if test takes too long, by using default abort
106      caused by SIGALRM.  */
107   int alarm_value = 5;
108   signal (SIGALRM, SIG_DFL);
109   alarm (alarm_value);
110 #endif
111
112   {
113     char buffer[256];
114     int result;
115
116     errno = 0;
117     result = ptsname_r (-1, buffer, sizeof buffer);
118     ASSERT (result != 0);
119     ASSERT (result == errno);
120     ASSERT (errno == EBADF || errno == ENOTTY);
121   }
122
123   {
124     int fd;
125     char buffer[256];
126     int result;
127
128     /* Open the controlling tty of the current process.  */
129     fd = open ("/dev/tty", O_RDONLY);
130     if (fd < 0)
131       {
132         fprintf (stderr, "Skipping test: cannot open controlling tty\n");
133         return 77;
134       }
135
136     result = ptsname_r (fd, buffer, sizeof buffer);
137     /* The result is usually NULL, because /dev/tty is a slave, not a
138        master.  */
139     if (result == 0)
140       {
141         ASSERT (memcmp (buffer, "/dev/", 5) == 0);
142       }
143
144     close (fd);
145   }
146
147 #if defined __sun
148   /* Solaris has BSD-style /dev/pty[p-r][0-9a-f] files, but the function
149      ptsname() does not work on them.  */
150   {
151     int fd;
152     char buffer[256];
153     int result;
154
155     /* Open a pty master.  */
156     fd = open ("/dev/ptmx", O_RDWR | O_NOCTTY);
157     if (fd < 0)
158       {
159         fprintf (stderr, "Skipping test: cannot open pseudo-terminal\n");
160         return 77;
161       }
162
163     result = ptsname_r (fd, buffer, sizeof buffer);
164     ASSERT (result == 0);
165     ASSERT (memcmp (buffer, "/dev/pts/", 9) == 0);
166
167     test_errors (fd, buffer);
168
169     close (fd);
170   }
171
172 #elif defined _AIX
173   /* AIX has BSD-style /dev/ptyp[0-9a-f] files, but the modern way to open
174      a pty is to go through /dev/ptc.  */
175   {
176     int fd;
177     char buffer[256];
178     int result;
179
180     /* Open a pty master.  */
181     fd = open ("/dev/ptc", O_RDWR | O_NOCTTY);
182     if (fd < 0)
183       {
184         fprintf (stderr, "Skipping test: cannot open pseudo-terminal\n");
185         return 77;
186       }
187
188     result = ptsname_r (fd, buffer, sizeof buffer);
189     ASSERT (result == 0);
190     ASSERT (memcmp (buffer, "/dev/pts/", 9) == 0);
191
192     test_errors (fd, buffer);
193
194     /* This call hangs on AIX.  */
195     close (fd);
196   }
197
198 #else
199
200   /* Try various master names of Mac OS X: /dev/pty[p-w][0-9a-f]  */
201   {
202     int char1;
203     int char2;
204
205     for (char1 = 'p'; char1 <= 'w'; char1++)
206       for (char2 = '0'; char2 <= 'f'; (char2 == '9' ? char2 = 'a' : char2++))
207         {
208           char master_name[32];
209           int fd;
210
211           sprintf (master_name, "/dev/pty%c%c", char1, char2);
212           fd = open (master_name, O_RDONLY);
213           if (fd >= 0)
214             {
215               char buffer[256];
216               int result;
217               char slave_name[32];
218
219               result = ptsname_r (fd, buffer, sizeof buffer);
220               ASSERT (result == 0);
221               sprintf (slave_name, "/dev/tty%c%c", char1, char2);
222               ASSERT (same_slave (buffer, slave_name));
223
224               test_errors (fd, buffer);
225
226               /* This call hangs on AIX.  */
227               close (fd);
228             }
229         }
230   }
231
232   /* Try various master names of *BSD: /dev/pty[p-sP-S][0-9a-v]  */
233   {
234     int upper;
235     int char1;
236     int char2;
237
238     for (upper = 0; upper <= 1; upper++)
239       for (char1 = (upper ? 'P' : 'p'); char1 <= (upper ? 'S' : 's'); char1++)
240         for (char2 = '0'; char2 <= 'v'; (char2 == '9' ? char2 = 'a' : char2++))
241           {
242             char master_name[32];
243             int fd;
244
245             sprintf (master_name, "/dev/pty%c%c", char1, char2);
246             fd = open (master_name, O_RDONLY);
247             if (fd >= 0)
248               {
249                 char buffer[256];
250                 int result;
251                 char slave_name[32];
252
253                 result = ptsname_r (fd, buffer, sizeof buffer);
254                 ASSERT (result == 0);
255                 sprintf (slave_name, "/dev/tty%c%c", char1, char2);
256                 ASSERT (same_slave (buffer, slave_name));
257
258                 test_errors (fd, buffer);
259
260                 close (fd);
261               }
262           }
263   }
264
265 #endif
266
267   return 0;
268 }