diff --git a/ChangeLog b/ChangeLog
index d352ed9..e7ad09a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2014-05-06  Aurelien Jarno  <aurelien@aurel32.net>
+
+	* sysdeps/unix/sysv/linux/ptsname.c (__ptsname_internal): return
+	errno if the TIOCGPTN ioctl fails with an error different than
+	EINVAL.
+	* login/tst-ptsname.c: New file.
+	* login/Makefile (tests): Add tst-ptsname.
+
 2014-05-05  Aurelien Jarno  <aurelien@aurel32.net>
 
 	* po/fr.po: Fix French translation of inappropriate.
diff --git a/login/Makefile b/login/Makefile
index ca55808..d758ac5 100644
--- a/login/Makefile
+++ b/login/Makefile
@@ -43,7 +43,7 @@ endif
 subdir-dirs = programs
 vpath %.c programs
 
-tests := tst-utmp tst-utmpx tst-grantpt
+tests := tst-utmp tst-utmpx tst-grantpt tst-ptsname
 
 # Build the -lutil library with these extra functions.
 extra-libs      := libutil
diff --git a/login/tst-ptsname.c b/login/tst-ptsname.c
new file mode 100644
index 0000000..a803863
--- /dev/null
+++ b/login/tst-ptsname.c
@@ -0,0 +1,138 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static int
+test_ok (int fd)
+{
+  int ret, err;
+  char buf[512];
+
+  ret = ptsname_r (fd, buf, sizeof (buf));
+  err = errno;
+
+  if (ret != 0)
+    {
+      printf ("ptsname_r(): expected: return = %d\n", 0);
+      printf ("             got: return = %d, errno = %d (%s)\n",
+	      ret, err, strerror (err));
+      return 1;
+    }
+
+  return 0;
+}
+
+static int
+test_einval (int fd)
+{
+  int ret, err;
+  char *buf = NULL;
+
+  ret = ptsname_r (fd, buf, 1);
+  err = errno;
+
+  if (ret == 0 || errno != EINVAL)
+    {
+      printf ("ptsname_r(): expected: return = %d, errno = %d\n", -1, EINVAL);
+      printf ("             got: return = %d, errno = %d (%s)\n",
+	      ret, err, strerror (err));
+      return 1;
+    }
+
+  return 0;
+}
+
+static int
+test_erange (int fd)
+{
+  int ret, err;
+  char buf[512];
+
+  /* We assume that the PTS name will always be more than one character. */
+  ret = ptsname_r (fd, buf, 1);
+  err = errno;
+
+  if (ret == 0 || errno != ERANGE)
+    {
+      printf ("ptsname_r(): expected: return = %d, errno = %d\n", -1, ERANGE);
+      printf ("             got: return = %d, errno = %d (%s)\n",
+	      ret, err, strerror (err));
+      return 1;
+    }
+
+  return 0;
+}
+
+static int
+test_enotty (void)
+{
+  int fd, ret, err;
+  const char file[] = "./ptsname-einval";
+  char buf[512];
+
+  /* First try with a normal file. */
+  fd = open (file, O_RDWR | O_CREAT, 0600);
+  if (fd == -1)
+    {
+      printf ("open(\"%s\", O_RDWR) failed\nerrno %d (%s)\n",
+	      file, errno, strerror (errno));
+      return 0;
+    }
+  unlink (file);
+
+  ret = ptsname_r (fd, buf, sizeof (buf));
+  err = errno;
+  close (fd);
+
+  if (ret == 0 || errno != ENOTTY)
+    {
+      printf ("ptsname_r(): expected: return = %d, errno = %d\n", -1, ENOTTY);
+      printf ("             got: return = %d, errno = %d (%s)\n",
+	      ret, err, strerror (err));
+      return 1;
+    }
+
+  /* Then try with a terminal device which is not a master. */
+  ret = ptsname_r (0, buf, sizeof (buf));
+  err = errno;
+
+  if (ret == 0 || errno != ENOTTY)
+    {
+      printf ("ptsname_r(): expected: return = %d, errno = %d\n", -1, ENOTTY);
+      printf ("             got: return = %d, errno = %d (%s)\n",
+	      ret, err, strerror (err));
+      return 1;
+    }
+
+  return 0;
+}
+
+int
+main (void)
+{
+  int result = 0;
+  int fd;
+
+  fd = posix_openpt (O_RDWR);
+  if (fd != -1)
+    {
+      result |= test_ok (fd);
+      result |= test_einval (fd);
+      result |= test_erange (fd);
+      close(fd);
+    }
+  else
+    {
+      printf ("posix_openpt(O_RDWR) failed\nerrno %d (%s)\n",
+	      errno, strerror (errno));
+      /* We don't fail because of this; maybe the system does not have
+	 SUS pseudo terminals.  */
+    }
+
+  result |= test_enotty ();
+
+  return result;
+}
diff --git a/sysdeps/unix/sysv/linux/ptsname.c b/sysdeps/unix/sysv/linux/ptsname.c
index ed39f8f..3fc14a7 100644
--- a/sysdeps/unix/sysv/linux/ptsname.c
+++ b/sysdeps/unix/sysv/linux/ptsname.c
@@ -105,7 +105,9 @@ __ptsname_internal (int fd, char *buf, size_t buflen, struct stat64 *stp)
 
       memcpy (__stpcpy (buf, devpts), p, &numbuf[sizeof (numbuf)] - p);
     }
-  else if (errno == EINVAL)
+  else if (errno != EINVAL)
+    return errno;
+  else
 #endif
     {
       char *p;
