Fix tst-setgetname for Linux kernels < 2.6.33.
[jlayton/glibc.git] / nptl / sysdeps / unix / sysv / linux / tst-setgetname.c
1 /* Test pthread_setname_np and pthread_getname_np.
2    Copyright (C) 2013-2014 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public License as
7    published by the Free Software Foundation; either version 2.1 of the
8    License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; see the file COPYING.LIB.  If
17    not, see <http://www.gnu.org/licenses/>.  */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <pthread.h>
21 #include <string.h>
22 #include <sys/syscall.h>
23 #include <unistd.h>
24 #include <fcntl.h>
25 #include <errno.h>
26 #include <kernel-features.h>
27
28 /* New name of process.  */
29 #define NEW_NAME "setname"
30
31 /* Name of process which is one byte too big
32    e.g. 17 bytes including null-terminator  */
33 #define BIG_NAME       "....V....X....XV"
34
35 /* Longest name of a process
36    e.g. 16 bytes including null-terminator.  */
37 #define LONGEST_NAME   "....V....X....X"
38
39 /* One less than longest name with unique
40    characters to detect modification.  */
41 #define CANARY_NAME    "abcdefghijklmn"
42
43 /* On Linux the maximum length of the name of a task *including* the null
44    terminator.  */
45 #define TASK_COMM_LEN 16
46
47 long
48 gettid (void)
49 {
50     return syscall(__NR_gettid);
51 }
52
53 /* On Linux we can read this task's name from /proc.  */
54 int
55 get_self_comm (long tid, char *buf, size_t len)
56 {
57   int res = 0;
58 #define FMT "/proc/self/task/%lu/comm"
59   char fname[sizeof (FMT) + 8];
60   sprintf (fname, FMT, (unsigned long) tid);
61
62   int fd = open (fname, O_RDONLY);
63   if (fd == -1)
64     return errno;
65
66   ssize_t n = read (fd, (void *) buf, len);
67   if (n < 0)
68     res = errno;
69   else
70     {
71       if (buf[n - 1] == '\n')
72         buf[n - 1] = '\0';
73       else if (n == len)
74         res = ERANGE;
75       else
76         buf[n] = '\0';
77     }
78
79   close (fd);
80   return res;
81 }
82
83 int
84 do_test (int argc, char **argv)
85 {
86   pthread_t self;
87   int res;
88   int ret = 0;
89   char name[TASK_COMM_LEN];
90   char name_check[TASK_COMM_LEN];
91
92   memset (name, '\0', TASK_COMM_LEN);
93   memset (name_check, '\0', TASK_COMM_LEN);
94
95   /* Test 1: Get the name of the task via pthread_getname_np and /proc
96      and verify that they both match.  */
97   self = pthread_self ();
98   res = pthread_getname_np (self, name, TASK_COMM_LEN);
99
100   if (res == 0)
101     {
102       res = get_self_comm (gettid (), name_check, TASK_COMM_LEN);
103
104 #if !__ASSUME_PROC_PID_TASK_COMM
105       /* On this first test we look for ENOENT to be returned from
106          get_self_comm to indicate that the kernel is older than
107          2.6.33 and doesn't contain comm within the proc structure.
108          In that case we skip the entire test.  */
109       if (res == ENOENT)
110         {
111           printf ("SKIP: The kernel does not have /proc/self/task/%%lu/comm.\n");
112           return 0;
113         }
114 #endif
115
116       if (res == 0)
117        {
118          if (strncmp (name, name_check, strlen (BIG_NAME)) == 0)
119            printf ("PASS: Test 1 - pthread_getname_np and /proc agree.\n");
120          else
121            {
122              printf ("FAIL: Test 1 - pthread_getname_np and /proc differ"
123                      " i.e. %s != %s\n", name, name_check);
124              ret++;
125            }
126        }
127       else
128        {
129          printf ("FAIL: Test 1 - unable read task name via proc.\n");
130          ret++;
131         }
132     }
133   else
134     {
135       printf ("FAIL: Test 1 - pthread_getname_np failed with error %d\n", res);
136       ret++;
137     }
138
139   /* Test 2: Test setting the name and then independently verify it
140              was set.  */
141   res = pthread_setname_np (self, NEW_NAME);
142
143   if (res == 0)
144     {
145       res = get_self_comm (gettid (), name_check, TASK_COMM_LEN);
146       if (res == 0)
147         {
148          if (strncmp (NEW_NAME, name_check, strlen (BIG_NAME)) == 0)
149            printf ("PASS: Test 2 - Value used in pthread_setname_np and"
150                    " /proc agree.\n");
151          else
152            {
153              printf ("FAIL: Test 2 - Value used in pthread_setname_np"
154                      " and /proc differ i.e. %s != %s\n",
155                      NEW_NAME, name_check);
156              ret++;
157            }
158         }
159       else
160        {
161          printf ("FAIL: Test 2 - unable to read task name via proc.\n");
162          ret++;
163         }
164     }
165   else
166     {
167       printf ("FAIL: Test 2 - pthread_setname_np failed with error %d\n", res);
168       ret++;
169     }
170
171   /* Test 3: Test setting a name that is one-byte too big.  */
172   res = pthread_getname_np (self, name, TASK_COMM_LEN);
173
174   if (res == 0)
175     {
176       res = pthread_setname_np (self, BIG_NAME);
177       if (res != 0)
178         {
179          if (res == ERANGE)
180            {
181              printf ("PASS: Test 3 - pthread_setname_np returned ERANGE"
182                      " for a process name that was too long.\n");
183
184              /* Verify the old name didn't change.  */
185              res = get_self_comm (gettid (), name_check, TASK_COMM_LEN);
186              if (res == 0)
187                {
188                  if (strncmp (name, name_check, strlen (BIG_NAME)) == 0)
189                    printf ("PASS: Test 3 - Original name unchanged after"
190                            " pthread_setname_np returned ERANGE.\n");
191                  else
192                    {
193                      printf ("FAIL: Test 3 - Original name changed after"
194                              " pthread_setname_np returned ERANGE"
195                              " i.e. %s != %s\n",
196                              name, name_check);
197                      ret++;
198                    }
199                }
200              else
201                {
202                  printf ("FAIL: Test 3 - unable to read task name.\n");
203                  ret++;
204                }
205            }
206          else
207            {
208              printf ("FAIL: Test 3 - Wrong error returned"
209                      " i.e. ERANGE != %d\n", res);
210              ret++;
211            }
212         }
213       else
214         {
215          printf ("FAIL: Test 3 - Too-long name accepted by"
216                  " pthread_setname_np.\n");
217          ret++;
218         }
219     }
220   else
221     {
222       printf ("FAIL: Test 3 - Unable to get original name.\n");
223       ret++;
224     }
225
226   /* Test 4: Verify that setting the longest name works.  */
227   res = pthread_setname_np (self, LONGEST_NAME);
228
229   if (res == 0)
230     {
231       res = get_self_comm (gettid (), name_check, TASK_COMM_LEN);
232       if (res == 0)
233         {
234          if (strncmp (LONGEST_NAME, name_check, strlen (BIG_NAME)) == 0)
235            printf ("PASS: Test 4 - Longest name set via pthread_setname_np"
236                    " agrees with /proc.\n");
237          else
238            {
239              printf ("FAIL: Test 4 - Value used in pthread_setname_np and /proc"
240                      " differ i.e. %s != %s\n", LONGEST_NAME, name_check);
241              ret++;
242            }
243         }
244       else
245        {
246          printf ("FAIL: Test 4 - unable to read task name via proc.\n");
247          ret++;
248         }
249     }
250   else
251     {
252       printf ("FAIL: Test 4 - pthread_setname_np failed with error %d\n", res);
253       ret++;
254     }
255
256   /* Test 5: Verify that getting a long name into a small buffer fails.  */
257   strncpy (name, CANARY_NAME, strlen (CANARY_NAME) + 1);
258
259   /* Claim the buffer length is strlen (LONGEST_NAME).  This is one character
260      too small to hold LONGEST_NAME *and* the null terminator.  We should get
261      back ERANGE and name should be unmodified.  */
262   res = pthread_getname_np (self, name, strlen (LONGEST_NAME));
263
264   if (res != 0)
265     {
266       if (res == ERANGE)
267         {
268           if (strncmp (CANARY_NAME, name, strlen (BIG_NAME)) == 0)
269             {
270               printf ("PASS: Test 5 - ERANGE and buffer unmodified.\n");
271             }
272           else
273             {
274               printf ("FAIL: Test 5 - Original buffer modified.\n");
275               ret++;
276             }
277         }
278       else
279         {
280           printf ("FAIL: Test 5 - Did not return ERANGE for small buffer.\n");
281           ret++;
282         }
283     }
284   else
285     {
286       printf ("FAIL: Test 5 - Returned name longer than buffer.\n");
287       ret++;
288     }
289
290   /* Test 6: Lastly make sure we can read back the longest name.  */
291   res = pthread_getname_np (self, name, strlen (LONGEST_NAME) + 1);
292
293   if (res == 0)
294     {
295       if (strncmp (LONGEST_NAME, name, strlen (BIG_NAME)) == 0)
296         {
297           printf ("PASS: Test 6 - Read back longest name correctly.\n");
298         }
299       else
300         {
301           printf ("FAIL: Test 6 - Read \"%s\" instead of longest name.\n",
302                   name);
303           ret++;
304         }
305     }
306   else
307     {
308       printf ("FAIL: Test 6 - pthread_getname_np failed with error %d\n", res);
309       ret++;
310     }
311
312   return ret;
313 }
314
315 #include <test-skeleton.c>