(root)/
glibc-2.38/
nptl/
tst-setgetname.c
       1  /* Test pthread_setname_np and pthread_getname_np.
       2     Copyright (C) 2013-2023 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 <https://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  
      27  /* New name of process.  */
      28  #define NEW_NAME "setname"
      29  
      30  /* Name of process which is one byte too big
      31     e.g. 17 bytes including null-terminator  */
      32  #define BIG_NAME       "....V....X....XV"
      33  
      34  /* Longest name of a process
      35     e.g. 16 bytes including null-terminator.  */
      36  #define LONGEST_NAME   "....V....X....X"
      37  
      38  /* One less than longest name with unique
      39     characters to detect modification.  */
      40  #define CANARY_NAME    "abcdefghijklmn"
      41  
      42  /* On Linux the maximum length of the name of a task *including* the null
      43     terminator.  */
      44  #define TASK_COMM_LEN 16
      45  
      46  /* On Linux we can read this task's name from /proc.  */
      47  int
      48  get_self_comm (long tid, char *buf, size_t len)
      49  {
      50    int res = 0;
      51  #define FMT "/proc/self/task/%lu/comm"
      52    char fname[sizeof (FMT) + 32];
      53    sprintf (fname, FMT, (unsigned long) tid);
      54  
      55    int fd = open (fname, O_RDONLY);
      56    if (fd == -1)
      57      return errno;
      58  
      59    ssize_t n = read (fd, (void *) buf, len);
      60    if (n < 0)
      61      res = errno;
      62    else
      63      {
      64        if (buf[n - 1] == '\n')
      65          buf[n - 1] = '\0';
      66        else if (n == len)
      67          res = ERANGE;
      68        else
      69          buf[n] = '\0';
      70      }
      71  
      72    close (fd);
      73    return res;
      74  }
      75  
      76  int
      77  do_test (int argc, char **argv)
      78  {
      79    pthread_t self;
      80    int res;
      81    int ret = 0;
      82    char name[TASK_COMM_LEN];
      83    char name_check[TASK_COMM_LEN];
      84  
      85    memset (name, '\0', TASK_COMM_LEN);
      86    memset (name_check, '\0', TASK_COMM_LEN);
      87  
      88    /* Test 1: Get the name of the task via pthread_getname_np and /proc
      89       and verify that they both match.  */
      90    self = pthread_self ();
      91    res = pthread_getname_np (self, name, TASK_COMM_LEN);
      92  
      93    if (res == 0)
      94      {
      95        res = get_self_comm (gettid (), name_check, TASK_COMM_LEN);
      96  
      97        if (res == 0)
      98         {
      99           if (strncmp (name, name_check, strlen (BIG_NAME)) == 0)
     100             printf ("PASS: Test 1 - pthread_getname_np and /proc agree.\n");
     101           else
     102             {
     103               printf ("FAIL: Test 1 - pthread_getname_np and /proc differ"
     104                       " i.e. %s != %s\n", name, name_check);
     105               ret++;
     106             }
     107         }
     108        else
     109         {
     110           printf ("FAIL: Test 1 - unable read task name via proc.\n");
     111           ret++;
     112          }
     113      }
     114    else
     115      {
     116        printf ("FAIL: Test 1 - pthread_getname_np failed with error %d\n", res);
     117        ret++;
     118      }
     119  
     120    /* Test 2: Test setting the name and then independently verify it
     121               was set.  */
     122    res = pthread_setname_np (self, NEW_NAME);
     123  
     124    if (res == 0)
     125      {
     126        res = get_self_comm (gettid (), name_check, TASK_COMM_LEN);
     127        if (res == 0)
     128          {
     129           if (strncmp (NEW_NAME, name_check, strlen (BIG_NAME)) == 0)
     130             printf ("PASS: Test 2 - Value used in pthread_setname_np and"
     131                     " /proc agree.\n");
     132           else
     133             {
     134               printf ("FAIL: Test 2 - Value used in pthread_setname_np"
     135  		     " and /proc differ i.e. %s != %s\n",
     136  		     NEW_NAME, name_check);
     137               ret++;
     138             }
     139          }
     140        else
     141         {
     142           printf ("FAIL: Test 2 - unable to read task name via proc.\n");
     143           ret++;
     144          }
     145      }
     146    else
     147      {
     148        printf ("FAIL: Test 2 - pthread_setname_np failed with error %d\n", res);
     149        ret++;
     150      }
     151  
     152    /* Test 3: Test setting a name that is one-byte too big.  */
     153    res = pthread_getname_np (self, name, TASK_COMM_LEN);
     154  
     155    if (res == 0)
     156      {
     157        res = pthread_setname_np (self, BIG_NAME);
     158        if (res != 0)
     159          {
     160           if (res == ERANGE)
     161             {
     162               printf ("PASS: Test 3 - pthread_setname_np returned ERANGE"
     163                       " for a process name that was too long.\n");
     164  
     165               /* Verify the old name didn't change.  */
     166               res = get_self_comm (gettid (), name_check, TASK_COMM_LEN);
     167               if (res == 0)
     168                 {
     169                   if (strncmp (name, name_check, strlen (BIG_NAME)) == 0)
     170                     printf ("PASS: Test 3 - Original name unchanged after"
     171                             " pthread_setname_np returned ERANGE.\n");
     172                   else
     173                     {
     174                       printf ("FAIL: Test 3 - Original name changed after"
     175                               " pthread_setname_np returned ERANGE"
     176                               " i.e. %s != %s\n",
     177                               name, name_check);
     178                       ret++;
     179                     }
     180                 }
     181               else
     182                 {
     183                   printf ("FAIL: Test 3 - unable to read task name.\n");
     184                   ret++;
     185                 }
     186             }
     187           else
     188             {
     189               printf ("FAIL: Test 3 - Wrong error returned"
     190  		     " i.e. ERANGE != %d\n", res);
     191               ret++;
     192             }
     193          }
     194        else
     195          {
     196           printf ("FAIL: Test 3 - Too-long name accepted by"
     197  	         " pthread_setname_np.\n");
     198           ret++;
     199          }
     200      }
     201    else
     202      {
     203        printf ("FAIL: Test 3 - Unable to get original name.\n");
     204        ret++;
     205      }
     206  
     207    /* Test 4: Verify that setting the longest name works.  */
     208    res = pthread_setname_np (self, LONGEST_NAME);
     209  
     210    if (res == 0)
     211      {
     212        res = get_self_comm (gettid (), name_check, TASK_COMM_LEN);
     213        if (res == 0)
     214          {
     215           if (strncmp (LONGEST_NAME, name_check, strlen (BIG_NAME)) == 0)
     216             printf ("PASS: Test 4 - Longest name set via pthread_setname_np"
     217                     " agrees with /proc.\n");
     218           else
     219             {
     220               printf ("FAIL: Test 4 - Value used in pthread_setname_np and /proc"
     221  		     " differ i.e. %s != %s\n", LONGEST_NAME, name_check);
     222               ret++;
     223             }
     224          }
     225        else
     226         {
     227           printf ("FAIL: Test 4 - unable to read task name via proc.\n");
     228           ret++;
     229          }
     230      }
     231    else
     232      {
     233        printf ("FAIL: Test 4 - pthread_setname_np failed with error %d\n", res);
     234        ret++;
     235      }
     236  
     237    /* Test 5: Verify that getting a long name into a small buffer fails.  */
     238    strncpy (name, CANARY_NAME, strlen (CANARY_NAME) + 1);
     239  
     240    /* Claim the buffer length is strlen (LONGEST_NAME).  This is one character
     241       too small to hold LONGEST_NAME *and* the null terminator.  We should get
     242       back ERANGE and name should be unmodified.  */
     243    res = pthread_getname_np (self, name, strlen (LONGEST_NAME));
     244  
     245    if (res != 0)
     246      {
     247        if (res == ERANGE)
     248          {
     249  	  if (strncmp (CANARY_NAME, name, strlen (BIG_NAME)) == 0)
     250  	    {
     251  	      printf ("PASS: Test 5 - ERANGE and buffer unmodified.\n");
     252  	    }
     253  	  else
     254  	    {
     255  	      printf ("FAIL: Test 5 - Original buffer modified.\n");
     256  	      ret++;
     257  	    }
     258          }
     259        else
     260          {
     261  	  printf ("FAIL: Test 5 - Did not return ERANGE for small buffer.\n");
     262  	  ret++;
     263          }
     264      }
     265    else
     266      {
     267        printf ("FAIL: Test 5 - Returned name longer than buffer.\n");
     268        ret++;
     269      }
     270  
     271    /* Test 6: Lastly make sure we can read back the longest name.  */
     272    res = pthread_getname_np (self, name, strlen (LONGEST_NAME) + 1);
     273  
     274    if (res == 0)
     275      {
     276        if (strncmp (LONGEST_NAME, name, strlen (BIG_NAME)) == 0)
     277          {
     278  	  printf ("PASS: Test 6 - Read back longest name correctly.\n");
     279          }
     280        else
     281          {
     282  	  printf ("FAIL: Test 6 - Read \"%s\" instead of longest name.\n",
     283  		  name);
     284  	  ret++;
     285          }
     286      }
     287    else
     288      {
     289        printf ("FAIL: Test 6 - pthread_getname_np failed with error %d\n", res);
     290        ret++;
     291      }
     292  
     293    return ret;
     294  }
     295  
     296  #include <test-skeleton.c>