root/maint/gnulib/tests/test-ptsname_r.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. same_slave
  2. test_errors
  3. main

   1 /* Test of ptsname_r(3).
   2    Copyright (C) 2010-2021 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 <https://www.gnu.org/licenses/>.  */
  16 
  17 /* Don't use __attribute__ __nonnull__ in this compilation unit.  Otherwise gcc
  18    may "optimize" the null_ptr function, when its result gets passed to a
  19    function that has an argument declared as _GL_ARG_NONNULL.  */
  20 #define _GL_ARG_NONNULL(params)
  21 
  22 #include <config.h>
  23 
  24 #include <stdlib.h>
  25 
  26 #include "signature.h"
  27 SIGNATURE_CHECK (ptsname_r, int, (int, char *, size_t));
  28 
  29 #include <errno.h>
  30 #include <fcntl.h>
  31 #include <signal.h>
  32 #include <stdio.h>
  33 #include <string.h>
  34 #include <unistd.h>
  35 #include <sys/stat.h>
  36 
  37 #include "same-inode.h"
  38 
  39 #if GNULIB_defined_ptsname_r
  40 # include "null-ptr.h"
  41 #endif
  42 
  43 #include "macros.h"
  44 
  45 /* Compare two slave names.
  46    On some systems, there are hard links in the /dev/ directory.
  47    For example, on OSF/1 5.1,
  48      /dev/ttyp0 == /dev/pts/0
  49      /dev/ttyp9 == /dev/pts/9
  50      /dev/ttypa == /dev/pts/10
  51      /dev/ttype == /dev/pts/14
  52  */
  53 static int
  54 same_slave (const char *slave_name1, const char *slave_name2)
     /* [previous][next][first][last][top][bottom][index][help] */
  55 {
  56   struct stat statbuf1;
  57   struct stat statbuf2;
  58 
  59   return (strcmp (slave_name1, slave_name2) == 0
  60           || (stat (slave_name1, &statbuf1) >= 0
  61               && stat (slave_name2, &statbuf2) >= 0
  62               && SAME_INODE (statbuf1, statbuf2)));
  63 }
  64 
  65 static void
  66 test_errors (int fd, const char *slave)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68   char buffer[256];
  69   size_t len;
  70   size_t buflen_max;
  71   size_t buflen;
  72   int result;
  73 
  74   len = strlen (slave);
  75   buflen_max = len + 5;
  76   if (buflen_max > sizeof buffer)
  77     buflen_max = sizeof buffer;
  78   for (buflen = 0; buflen <= buflen_max; buflen++)
  79     {
  80       memset (buffer, 'X', sizeof buffer);
  81       result = ptsname_r (fd, buffer, buflen);
  82       if (buflen > len)
  83         {
  84           ASSERT (result == 0);
  85           ASSERT (buffer[0] == '/');
  86         }
  87       else
  88         {
  89           ASSERT (result != 0);
  90           ASSERT (result == ERANGE);
  91           ASSERT (buffer[0] == 'X');
  92         }
  93     }
  94 
  95   /* This test works only if the ptsname_r implementation comes from gnulib.
  96      If it comes from libc, we have no way to prevent gcc from "optimizing"
  97      the null_ptr function in invalid ways.  See
  98      <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93156>.  */
  99 #if GNULIB_defined_ptsname_r
 100   result = ptsname_r (fd, null_ptr (), 0);
 101   ASSERT (result != 0);
 102   ASSERT (result == EINVAL);
 103 #endif
 104 }
 105 
 106 int
 107 main (void)
     /* [previous][next][first][last][top][bottom][index][help] */
 108 {
 109 #if HAVE_DECL_ALARM
 110   /* Declare failure if test takes too long, by using default abort
 111      caused by SIGALRM.  */
 112 # if defined _AIX
 113   int alarm_value = 20;
 114 # else
 115   int alarm_value = 5;
 116 # endif
 117   signal (SIGALRM, SIG_DFL);
 118   alarm (alarm_value);
 119 #endif
 120 
 121   {
 122     char buffer[256];
 123     int result;
 124 
 125     result = ptsname_r (-1, buffer, sizeof buffer);
 126     ASSERT (result != 0);
 127     ASSERT (result == EBADF || result == ENOTTY);
 128   }
 129 
 130   {
 131     int fd;
 132     char buffer[256];
 133     int result;
 134 
 135     /* Open the controlling tty of the current process.  */
 136     fd = open ("/dev/tty", O_RDONLY);
 137     if (fd < 0)
 138       {
 139         fprintf (stderr, "Skipping test: cannot open controlling tty\n");
 140         return 77;
 141       }
 142 
 143     result = ptsname_r (fd, buffer, sizeof buffer);
 144     /* The result is usually NULL, because /dev/tty is a slave, not a
 145        master.  */
 146     if (result == 0)
 147       {
 148         ASSERT (memcmp (buffer, "/dev/", 5) == 0);
 149       }
 150 
 151     close (fd);
 152   }
 153 
 154 #if defined __sun || defined __DragonFly__
 155   /* Solaris has BSD-style /dev/pty[p-r][0-9a-f] files, but the function
 156      ptsname() does not work on them.
 157      DragonFly BSD has only /dev/ptmx.  */
 158   {
 159     int fd;
 160     char buffer[256];
 161     int result;
 162 
 163     /* Open a pty master.  */
 164     fd = open ("/dev/ptmx", O_RDWR | O_NOCTTY);
 165     if (fd < 0)
 166       {
 167         fprintf (stderr, "Skipping test: cannot open pseudo-terminal\n");
 168         return 77;
 169       }
 170 
 171     result = ptsname_r (fd, buffer, sizeof buffer);
 172     ASSERT (result == 0);
 173     ASSERT (memcmp (buffer, "/dev/pts/", 9) == 0);
 174 
 175     test_errors (fd, buffer);
 176 
 177     close (fd);
 178   }
 179 
 180 #elif defined _AIX
 181   /* AIX has BSD-style /dev/ptyp[0-9a-f] files, and the function ptsname()
 182      produces the corresponding /dev/ttyp[0-9a-f] file for each.  But opening
 183      such a pty causes the process to hang in a state where it does not even
 184      react to the SIGALRM signal for N * 15 seconds, where N is the number of
 185      opened ptys, either in the close (fd) call or - when this close (fd) call
 186      is commented out - at the process exit.
 187      So, better don't use these BSD-style ptys.  The modern way to open a pty
 188      is to go through /dev/ptc.  */
 189   {
 190     int fd;
 191     char buffer[256];
 192     int result;
 193 
 194     /* Open a pty master.  */
 195     fd = open ("/dev/ptc", O_RDWR | O_NOCTTY);
 196     if (fd < 0)
 197       {
 198         fprintf (stderr, "Skipping test: cannot open pseudo-terminal\n");
 199         return 77;
 200       }
 201 
 202     result = ptsname_r (fd, buffer, sizeof buffer);
 203     ASSERT (result == 0);
 204     ASSERT (memcmp (buffer, "/dev/pts/", 9) == 0);
 205 
 206     test_errors (fd, buffer);
 207 
 208     /* This close (fd) call takes 15 seconds.  It would be interruptible by the
 209        SIGALRM timer, but then this test would report failure.  */
 210     close (fd);
 211   }
 212 
 213 #else
 214 
 215   /* Try various master names of Mac OS X: /dev/pty[p-w][0-9a-f]  */
 216   {
 217     int char1;
 218     int char2;
 219 
 220     for (char1 = 'p'; char1 <= 'w'; char1++)
 221       for (char2 = '0'; char2 <= 'f'; (char2 == '9' ? char2 = 'a' : char2++))
 222         {
 223           char master_name[32];
 224           int fd;
 225 
 226           sprintf (master_name, "/dev/pty%c%c", char1, char2);
 227           fd = open (master_name, O_RDONLY);
 228           if (fd >= 0)
 229             {
 230               char buffer[256];
 231               int result;
 232               char slave_name[32];
 233 
 234               result = ptsname_r (fd, buffer, sizeof buffer);
 235               ASSERT (result == 0);
 236               sprintf (slave_name, "/dev/tty%c%c", char1, char2);
 237               ASSERT (same_slave (buffer, slave_name));
 238 
 239               test_errors (fd, buffer);
 240 
 241               /* This call hangs on AIX.  */
 242               close (fd);
 243             }
 244         }
 245   }
 246 
 247   /* Try various master names of *BSD: /dev/pty[p-sP-S][0-9a-v]  */
 248   {
 249     int upper;
 250     int char1;
 251     int char2;
 252 
 253     for (upper = 0; upper <= 1; upper++)
 254       for (char1 = (upper ? 'P' : 'p'); char1 <= (upper ? 'S' : 's'); char1++)
 255         for (char2 = '0'; char2 <= 'v'; (char2 == '9' ? char2 = 'a' : char2++))
 256           {
 257             char master_name[32];
 258             int fd;
 259 
 260             sprintf (master_name, "/dev/pty%c%c", char1, char2);
 261             fd = open (master_name, O_RDONLY);
 262             if (fd >= 0)
 263               {
 264                 char buffer[256];
 265                 int result;
 266                 char slave_name[32];
 267 
 268                 result = ptsname_r (fd, buffer, sizeof buffer);
 269                 ASSERT (result == 0);
 270                 sprintf (slave_name, "/dev/tty%c%c", char1, char2);
 271                 ASSERT (same_slave (buffer, slave_name));
 272 
 273                 test_errors (fd, buffer);
 274 
 275                 close (fd);
 276               }
 277           }
 278   }
 279 
 280 #endif
 281 
 282   return 0;
 283 }

/* [previous][next][first][last][top][bottom][index][help] */