diff --git a/libio/iovsscanf.c b/libio/iovsscanf.c
index e56ab8bd7d..ee6a99ec6a 100644
--- a/libio/iovsscanf.c
+++ b/libio/iovsscanf.c
@@ -24,22 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include "libioP.h"
 #include "strfile.h"
 
 int
 _IO_vsscanf (const char *string, const char *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
-  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_read (&sf, string);
+  return __vfscanf_internal (f, format, args, 0);
 }
 ldbl_weak_alias (_IO_vsscanf, __vsscanf)
 ldbl_weak_alias (_IO_vsscanf, vsscanf)
diff --git a/libio/iovswscanf.c b/libio/iovswscanf.c
index 5bd1c88412..cb9cbe15cc 100644
--- a/libio/iovswscanf.c
+++ b/libio/iovswscanf.c
@@ -24,24 +24,16 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include "libioP.h"
-#include "strfile.h"
 #include <wchar.h>
+#include "strfile.h"
 
 int
 __vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
   struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
-  _IO_fwide (&sf._sbf._f, 1);
-  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
-  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_readw (&sf, &wd, string);
+  return __vfwscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__vswscanf)
 ldbl_hidden_def (__vswscanf, vswscanf)
diff --git a/libio/libio.h b/libio/libio.h
index 00f9169613..d4eba2df54 100644
--- a/libio/libio.h
+++ b/libio/libio.h
@@ -321,7 +321,6 @@ libc_hidden_proto (_IO_padn)
 libc_hidden_proto (_IO_putc)
 libc_hidden_proto (_IO_sgetn)
 libc_hidden_proto (_IO_vfprintf)
-libc_hidden_proto (_IO_vfscanf)
 
 #ifdef _IO_MTSAFE_IO
 # undef _IO_peekc
diff --git a/libio/libioP.h b/libio/libioP.h
index 8afe7032e3..a471c90be8 100644
--- a/libio/libioP.h
+++ b/libio/libioP.h
@@ -704,6 +704,15 @@ extern off64_t _IO_seekpos_unlocked (FILE *, off64_t, int)
 
 #endif /* _G_HAVE_MMAP */
 
+/* Flags for __vfscanf_internal and __vfwscanf_internal.  */
+#define SCANF_LDBL_IS_DBL 0x0001
+#define SCANF_ISOC99_A    0x0002
+
+extern int __vfscanf_internal (FILE *fp, const char *format, va_list argp,
+                               unsigned int flags);
+extern int __vfwscanf_internal (FILE *fp, const wchar_t *format, va_list argp,
+                                unsigned int flags);
+
 extern int _IO_vscanf (const char *, va_list) __THROW;
 
 #ifdef _IO_MTSAFE_IO
diff --git a/libio/strfile.h b/libio/strfile.h
index 46ac81809a..715149f5bd 100644
--- a/libio/strfile.h
+++ b/libio/strfile.h
@@ -24,7 +24,9 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <stdio.h>
+#ifndef STRFILE_H_
+#define STRFILE_H_
+
 #include "libioP.h"
 
 typedef void *(*_IO_alloc_type) (size_t);
@@ -81,3 +83,32 @@ typedef struct
 } _IO_wstrnfile;
 
 extern const struct _IO_jump_t _IO_wstrn_jumps attribute_hidden;
+
+/* Initialize an _IO_strfile SF to read from narrow string STRING, and
+   return the corresponding FILE object.  It is not necessary to fclose
+   the FILE when it is no longer needed.  */
+static inline FILE *
+_IO_strfile_read (_IO_strfile *sf, const char *string)
+{
+  sf->_sbf._f._lock = NULL;
+  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
+  _IO_JUMPS (&sf->_sbf) = &_IO_str_jumps;
+  _IO_str_init_static_internal (sf, (char*)string, 0, NULL);
+  return &sf->_sbf._f;
+}
+
+/* Initialize an _IO_strfile SF and _IO_wide_data WD to read from wide
+   string STRING, and return the corresponding FILE object.  It is not
+   necessary to fclose the FILE when it is no longer needed.  */
+static inline FILE *
+_IO_strfile_readw (_IO_strfile *sf, struct _IO_wide_data *wd,
+                   const wchar_t *string)
+{
+  sf->_sbf._f._lock = NULL;
+  _IO_no_init (&sf->_sbf._f, _IO_USER_LOCK, 0, wd, &_IO_wstr_jumps);
+  _IO_fwide (&sf->_sbf._f, 1);
+  _IO_wstr_init_static (&sf->_sbf._f, (wchar_t *)string, 0, NULL);
+  return &sf->_sbf._f;
+}
+
+#endif /* strfile.h.  */
diff --git a/libio/swscanf.c b/libio/swscanf.c
index c8686bcbaf..90f721cc51 100644
--- a/libio/swscanf.c
+++ b/libio/swscanf.c
@@ -15,20 +15,22 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#include <libioP.h>
 #include <stdarg.h>
-#include <wchar.h>
+#include "strfile.h"
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __swscanf (const wchar_t *s, const wchar_t *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
 
   va_start (arg, format);
-  done = __vswscanf (s, format, arg);
+  done = __vfwscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/libio/vscanf.c b/libio/vscanf.c
index 9c27122c27..a3e2dd43f2 100644
--- a/libio/vscanf.c
+++ b/libio/vscanf.c
@@ -32,6 +32,6 @@
 int
 _IO_vscanf (const char *format, va_list args)
 {
-  return _IO_vfscanf (_IO_stdin, format, args, NULL);
+  return __vfscanf_internal (_IO_stdin, format, args, 0);
 }
 ldbl_weak_alias (_IO_vscanf, vscanf)
diff --git a/libio/vwscanf.c b/libio/vwscanf.c
index 0d5f558758..7af770c8c3 100644
--- a/libio/vwscanf.c
+++ b/libio/vwscanf.c
@@ -30,6 +30,6 @@
 int
 __vwscanf (const wchar_t *format, va_list args)
 {
-  return _IO_vfwscanf (_IO_stdin, format, args, NULL);
+  return __vfwscanf_internal (_IO_stdin, format, args, 0);
 }
 ldbl_strong_alias (__vwscanf, vwscanf)
diff --git a/libio/wscanf.c b/libio/wscanf.c
index c8cdad0acd..fe27ff6fa6 100644
--- a/libio/wscanf.c
+++ b/libio/wscanf.c
@@ -30,7 +30,7 @@ __wscanf (const wchar_t *format, ...)
   int done;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stdin, format, arg, NULL);
+  done = __vfwscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/Makefile b/stdio-common/Makefile
index 9dfc115313..b7b1f01bdd 100644
--- a/stdio-common/Makefile
+++ b/stdio-common/Makefile
@@ -39,7 +39,8 @@ routines	:=							      \
 	flockfile ftrylockfile funlockfile				      \
 	isoc99_scanf isoc99_vscanf isoc99_fscanf isoc99_vfscanf isoc99_sscanf \
 	isoc99_vsscanf							      \
-	psiginfo gentempfd
+	psiginfo gentempfd						      \
+	vfscanf-internal vfwscanf-internal iovfscanf iovfwscanf
 
 aux	:= errlist siglist printf-parsemb printf-parsewc fxprintf
 
diff --git a/stdio-common/Versions b/stdio-common/Versions
index 5016f69c20..7af44949f7 100644
--- a/stdio-common/Versions
+++ b/stdio-common/Versions
@@ -57,6 +57,9 @@ libc {
     psiginfo;
     register_printf_modifier; register_printf_type; register_printf_specifier;
   }
+  GLIBC_2.28 {
+    # SHLIB_COMPAT(GLIBC_2_0, GLIBC_2_28) used in iovfscanf.c etc
+  }
   GLIBC_PRIVATE {
     # global variables
     _itoa_lower_digits;
diff --git a/stdio-common/iovfscanf.c b/stdio-common/iovfscanf.c
new file mode 100644
index 0000000000..fb347d60cb
--- /dev/null
+++ b/stdio-common/iovfscanf.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libioP.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+
+int
+attribute_compat_text_section
+__IO_vfscanf (FILE *fp, const char *format, va_list ap, int *errp)
+{
+  int rv = __vfscanf_internal (fp, format, ap, 0);
+  if (__glibc_unlikely (errp != 0))
+    *errp = (rv == -1);
+  return rv;
+}
+ldbl_compat_symbol (libc, __IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+
+#endif
diff --git a/stdio-common/iovfwscanf.c b/stdio-common/iovfwscanf.c
new file mode 100644
index 0000000000..73936f68b2
--- /dev/null
+++ b/stdio-common/iovfwscanf.c
@@ -0,0 +1,34 @@
+/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libioP.h>
+#include <shlib-compat.h>
+
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
+
+int
+attribute_compat_text_section
+__IO_vfwscanf (FILE *fp, const wchar_t *format, va_list ap, int *errp)
+{
+  int rv = __vfwscanf_internal (fp, format, ap, 0);
+  if (__glibc_unlikely (errp != 0))
+    *errp = (rv == -1);
+  return rv;
+}
+compat_symbol (libc, __IO_vfwscanf, _IO_vfwscanf, GLIBC_2_0);
+
+#endif
diff --git a/stdio-common/isoc99_fscanf.c b/stdio-common/isoc99_fscanf.c
index 9cdf85e679..4210d11f2b 100644
--- a/stdio-common/isoc99_fscanf.c
+++ b/stdio-common/isoc99_fscanf.c
@@ -31,7 +31,7 @@ __isoc99_fscanf (FILE *stream, const char *format, ...)
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stream, format, arg, NULL);
+  done = __vfscanf_internal (stream, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stream);
diff --git a/stdio-common/isoc99_scanf.c b/stdio-common/isoc99_scanf.c
index bf7dbe86bb..64c873eed9 100644
--- a/stdio-common/isoc99_scanf.c
+++ b/stdio-common/isoc99_scanf.c
@@ -34,7 +34,7 @@ __isoc99_scanf (const char *format, ...)
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
+  done = __vfscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
 #ifdef _IO_MTSAFE_IO
diff --git a/stdio-common/isoc99_sscanf.c b/stdio-common/isoc99_sscanf.c
index 56a60a2c05..95b94a68b5 100644
--- a/stdio-common/isoc99_sscanf.c
+++ b/stdio-common/isoc99_sscanf.c
@@ -16,8 +16,7 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
 /* VARARGS2 */
@@ -26,9 +25,12 @@ __isoc99_sscanf (const char *s, const char *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __isoc99_vsscanf (s, format, arg);
+  done = __vfscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/isoc99_vfscanf.c b/stdio-common/isoc99_vfscanf.c
index b80e05f8db..c96ca831ae 100644
--- a/stdio-common/isoc99_vfscanf.c
+++ b/stdio-common/isoc99_vfscanf.c
@@ -27,7 +27,7 @@ __isoc99_vfscanf (FILE *stream, const char *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stream);
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfscanf (stream, format, args, NULL);
+  done = __vfscanf_internal (stream, format, args, 0);
   _IO_release_lock (stream);
   return done;
 }
diff --git a/stdio-common/isoc99_vscanf.c b/stdio-common/isoc99_vscanf.c
index 0b747f85ba..72ae72ddee 100644
--- a/stdio-common/isoc99_vscanf.c
+++ b/stdio-common/isoc99_vscanf.c
@@ -27,7 +27,7 @@ __isoc99_vscanf (const char *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stdin);
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfscanf (stdin, format, args, NULL);
+  done = __vfscanf_internal (stdin, format, args, 0);
   _IO_release_lock (stdin);
   return done;
 }
diff --git a/stdio-common/isoc99_vsscanf.c b/stdio-common/isoc99_vsscanf.c
index ac85ef2d0d..02bc0f50e6 100644
--- a/stdio-common/isoc99_vsscanf.c
+++ b/stdio-common/isoc99_vsscanf.c
@@ -24,23 +24,14 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <libioP.h>
-#include <stdio.h>
-#include "../libio/strfile.h"
+#include <libio/strfile.h>
 
 int
 __isoc99_vsscanf (const char *string, const char *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, -1, NULL, NULL);
-  _IO_JUMPS (&sf._sbf) = &_IO_str_jumps;
-  _IO_str_init_static_internal (&sf, (char*)string, 0, NULL);
-  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
-  ret = _IO_vfscanf (&sf._sbf._f, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_read (&sf, string);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+  return __vfscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__isoc99_vsscanf)
diff --git a/stdio-common/scanf.c b/stdio-common/scanf.c
index e61b5f1ad3..de38d70353 100644
--- a/stdio-common/scanf.c
+++ b/stdio-common/scanf.c
@@ -30,7 +30,7 @@ __scanf (const char *format, ...)
   int done;
 
   va_start (arg, format);
-  done = _IO_vfscanf (stdin, format, arg, NULL);
+  done = __vfscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/stdio-common/sscanf.c b/stdio-common/sscanf.c
index 88cd641798..e25e9c27a5 100644
--- a/stdio-common/sscanf.c
+++ b/stdio-common/sscanf.c
@@ -16,26 +16,24 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
-#define __vsscanf(s, f, a) _IO_vsscanf (s, f, a)
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __sscanf (const char *s, const char *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  FILE *f = _IO_strfile_read (&sf, s);
 
   va_start (arg, format);
-  done = __vsscanf (s, format, arg);
+  done = __vfscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
 }
 ldbl_hidden_def (__sscanf, sscanf)
 ldbl_strong_alias (__sscanf, sscanf)
-#undef _IO_sscanf
-/* This is for libg++.  */
 ldbl_strong_alias (__sscanf, _IO_sscanf)
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf-internal.c
similarity index 98%
rename from stdio-common/vfscanf.c
rename to stdio-common/vfscanf-internal.c
index 3263268c7e..93b07ad4bc 100644
--- a/stdio-common/vfscanf.c
+++ b/stdio-common/vfscanf-internal.c
@@ -132,16 +132,13 @@
 #include "printf-parse.h" /* Use read_int.  */
 
 #define encode_error() do {						      \
-			  errval = 4;					      \
 			  __set_errno (EILSEQ);				      \
 			  goto errout;					      \
 			} while (0)
 #define conv_error()	do {						      \
-			  errval = 2;					      \
 			  goto errout;					      \
 			} while (0)
 #define input_error()	do {						      \
-			  errval = 1;					      \
 			  if (done == 0) done = EOF;			      \
 			  goto errout;					      \
 			} while (0)
@@ -267,12 +264,12 @@ char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
    Return the number of assignments made, or -1 for an input error.  */
 #ifdef COMPILE_WSCANF
 int
-_IO_vfwscanf (FILE *s, const wchar_t *format, va_list argptr,
-	      int *errp)
+__vfwscanf_internal (FILE *s, const wchar_t *format, va_list argptr,
+                     unsigned int mode_flags)
 #else
 int
-_IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
-		      int *errp)
+__vfscanf_internal (FILE *s, const char *format, va_list argptr,
+                    unsigned int mode_flags)
 #endif
 {
   va_list arg;
@@ -283,7 +280,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   WINT_T c = 0;	/* Last char read.  */
   int width;		/* Maximum field width.  */
   int flags;		/* Modifiers for current format element.  */
-  int errval = 0;
 #ifndef COMPILE_WSCANF
   locale_t loc = _NL_CURRENT_LOCALE;
   struct __locale_data *const curctype = loc->__locales[LC_CTYPE];
@@ -335,6 +331,14 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   struct char_buffer charbuf;
   scratch_buffer_init (&charbuf.scratch);
 
+#define LDBL_DISTINCT (__glibc_likely ((mode_flags & SCANF_LDBL_IS_DBL) == 0))
+#define USE_ISOC99_A  (__glibc_likely (mode_flags & SCANF_ISOC99_A))
+  /* Temporarily honor the environmental mode bits.  */
+  if (__ldbl_is_dbl)
+    mode_flags |= SCANF_LDBL_IS_DBL;
+  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+    mode_flags |= SCANF_ISOC99_A;
+
 #ifdef __va_copy
   __va_copy (arg, argptr);
 #else
@@ -566,7 +570,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	    }
 	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
 	     supported at all.  */
-	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
+	  if (USE_ISOC99_A)
 	    {
 	      --f;
 	      break;
@@ -2422,7 +2426,7 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
 	      done = EOF;
 	      goto errout;
 	    }
-	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
+	  if ((flags & LONGDBL) && LDBL_DISTINCT)
 	    {
 	      long double d = __strtold_internal
 		(char_buffer_start (&charbuf), &tw, flags & GROUP);
@@ -3017,8 +3021,6 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
   UNLOCK_STREAM (s);
 
   scratch_buffer_free (&charbuf.scratch);
-  if (errp != NULL)
-    *errp |= errval;
 
   if (__glibc_unlikely (done == EOF))
     {
@@ -3044,23 +3046,3 @@ _IO_vfscanf_internal (FILE *s, const char *format, va_list argptr,
     }
   return done;
 }
-
-#ifdef COMPILE_WSCANF
-int
-__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
-{
-  return _IO_vfwscanf (s, format, argptr, NULL);
-}
-ldbl_weak_alias (__vfwscanf, vfwscanf)
-#else
-int
-___vfscanf (FILE *s, const char *format, va_list argptr)
-{
-  return _IO_vfscanf_internal (s, format, argptr, NULL);
-}
-ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
-ldbl_strong_alias (___vfscanf, __vfscanf)
-ldbl_hidden_def (___vfscanf, __vfscanf)
-ldbl_weak_alias (___vfscanf, vfscanf)
-#endif
diff --git a/stdio-common/vfscanf.c b/stdio-common/vfscanf.c
index 0000000000..5eedca8340 100644
--- /dev/null	2018-02-21 11:21:31.435874074 -0500
+++ b/stdio-common/vfscanf.c	2018-03-07 08:44:37.578545222 -0500
@@ -0,0 +1,27 @@
+/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libioP.h>
+
+int
+___vfscanf (FILE *s, const char *format, va_list argptr)
+{
+  return __vfscanf_internal (s, format, argptr, 0);
+}
+ldbl_strong_alias (___vfscanf, __vfscanf)
+ldbl_hidden_def (___vfscanf, __vfscanf)
+ldbl_weak_alias (___vfscanf, vfscanf)
diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf-internal.c
similarity index 50%
rename from stdio-common/vfscanf.c
rename to stdio-common/vfscanf-internal.c
index 26b1a66608..26c89270b7 100644
--- a/stdio-common/vfwscanf.c
+++ b/stdio-common/vfwscanf-internal.c
@@ -1,2 +1,2 @@
 #define COMPILE_WSCANF	1
-#include "vfscanf.c"
+#include "vfscanf-internal.c"
diff --git a/stdio-common/vfwscanf.c b/stdio-common/vfwscanf.c
new file mode 100644
index 0000000000..0554b7eae1
--- a/stdio-common/vfwscanf.c
+++ b/stdio-common/vfwscanf.c
@@ -0,0 +1,25 @@
+/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, see
+   <http://www.gnu.org/licenses/>.  */
+
+#include <libioP.h>
+
+int
+__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
+{
+  return __vfwscanf_internal (s, format, argptr, 0);
+}
+ldbl_weak_alias (__vfwscanf, vfwscanf)
diff --git a/sysdeps/generic/math_ldbl_opt.h b/sysdeps/generic/math_ldbl_opt.h
index 8a5d8ba107..92f670dff7 100644
--- a/sysdeps/generic/math_ldbl_opt.h
+++ b/sysdeps/generic/math_ldbl_opt.h
@@ -6,9 +6,13 @@
    for platforms where compatibility symbols are required for a previous
    ABI that defined long double functions as aliases for the double code.  */
 
+#include <shlib-compat.h>
+
 #define LONG_DOUBLE_COMPAT(lib, introduced) 0
 #define long_double_symbol(lib, local, symbol)
 #define ldbl_hidden_def(local, name) libc_hidden_def (name)
 #define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
 #define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
+#define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, version)
 #define __ldbl_is_dbl 0
diff --git a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
index af861c11ea..ee70d085fd 100644
--- a/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
+++ b/sysdeps/ieee754/ldbl-opt/math_ldbl_opt.h
@@ -20,10 +20,14 @@
   long_double_symbol (libc, __GL_##name##_##aliasname, aliasname);
 # define long_double_symbol_1(lib, local, symbol, version) \
   versioned_symbol (lib, local, symbol, version)
+# define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, LONG_DOUBLE_COMPAT_VERSION)
 #else
 # define ldbl_hidden_def(local, name) libc_hidden_def (name)
 # define ldbl_strong_alias(name, aliasname) strong_alias (name, aliasname)
 # define ldbl_weak_alias(name, aliasname) weak_alias (name, aliasname)
+# define ldbl_compat_symbol(lib, local, symbol, version) \
+  compat_symbol (lib, local, symbol, version)
 # ifndef __ASSEMBLER__
 /* Note that weak_alias cannot be used - it is defined to nothing
    in most of the C files.  */
diff --git a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
index 7d19eaba8d..9ac88deb74 100644
--- a/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
+++ b/sysdeps/ieee754/ldbl-opt/nldbl-compat.c
@@ -329,16 +329,20 @@ __nldbl_wprintf (const wchar_t *fmt, ...)
   return done;
 }
 
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
 int
 attribute_compat_text_section
 __nldbl__IO_vfscanf (FILE *s, const char *fmt, va_list ap, int *errp)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfscanf (s, fmt, ap, errp);
+  res = __vfscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
+  if (__glibc_unlikely (errp != 0))
+    *errp = (res == -1);
   return res;
 }
+#endif
 
 int
 attribute_compat_text_section
@@ -346,7 +350,7 @@ __nldbl___vfscanf (FILE *s, const char *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfscanf (s, fmt, ap, NULL);
+  res = __vfscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return res;
 }
@@ -422,7 +426,7 @@ __nldbl_vfwscanf (FILE *s, const wchar_t *fmt, va_list ap)
 {
   int res;
   set_no_long_double ();
-  res = _IO_vfwscanf (s, fmt, ap, NULL);
+  res = __vfwscanf_internal (s, fmt, ap, 0);
   clear_no_long_double ();
   return res;
 }
@@ -1026,7 +1030,9 @@ compat_symbol (libc, __nldbl_vdprintf, vdprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_vsnprintf, vsnprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_vsprintf, vsprintf, GLIBC_2_0);
 compat_symbol (libc, __nldbl__IO_sscanf, _IO_sscanf, GLIBC_2_0);
+#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_28)
 compat_symbol (libc, __nldbl__IO_vfscanf, _IO_vfscanf, GLIBC_2_0);
+#endif
 compat_symbol (libc, __nldbl___vfscanf, __vfscanf, GLIBC_2_0);
 compat_symbol (libc, __nldbl___vsscanf, __vsscanf, GLIBC_2_0);
 compat_symbol (libc, __nldbl_fscanf, fscanf, GLIBC_2_0);
diff --git a/wcsmbs/isoc99_fwscanf.c b/wcsmbs/isoc99_fwscanf.c
index 0c6a2c47ac..00b07dd48e 100644
--- a/wcsmbs/isoc99_fwscanf.c
+++ b/wcsmbs/isoc99_fwscanf.c
@@ -32,7 +32,7 @@ __isoc99_fwscanf (FILE *stream, const wchar_t *format, ...)
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stream, format, arg, NULL);
+  done = __vfwscanf_internal (stream, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stream);
diff --git a/wcsmbs/isoc99_swscanf.c b/wcsmbs/isoc99_swscanf.c
index ff523db706..40401d0aa1 100644
--- a/wcsmbs/isoc99_swscanf.c
+++ b/wcsmbs/isoc99_swscanf.c
@@ -16,20 +16,22 @@
    <http://www.gnu.org/licenses/>.  */
 
 #include <stdarg.h>
-#include <stdio.h>
-#include <libioP.h>
-#include <wchar.h>
+#include <libio/strfile.h>
 
 /* Read formatted input from S, according to the format string FORMAT.  */
-/* VARARGS2 */
+
 int
 __isoc99_swscanf (const wchar_t *s, const wchar_t *format, ...)
 {
   va_list arg;
   int done;
+  _IO_strfile sf;
+  struct _IO_wide_data wd;
+  FILE *f = _IO_strfile_readw (&sf, &wd, s);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = __isoc99_vswscanf (s, format, arg);
+  done = __vfwscanf_internal (f, format, arg, 0);
   va_end (arg);
 
   return done;
diff --git a/wcsmbs/isoc99_vfwscanf.c b/wcsmbs/isoc99_vfwscanf.c
index 7beb45b4d3..f70c6b596d 100644
--- a/wcsmbs/isoc99_vfwscanf.c
+++ b/wcsmbs/isoc99_vfwscanf.c
@@ -28,7 +28,7 @@ __isoc99_vfwscanf (FILE *stream, const wchar_t *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stream);
   stream->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfwscanf (stream, format, args, NULL);
+  done = __vfwscanf_internal (stream, format, args, 0);
   _IO_release_lock (stream);
   return done;
 }
diff --git a/wcsmbs/isoc99_vswscanf.c b/wcsmbs/isoc99_vswscanf.c
index 130769154d..b91eb651a3 100644
--- a/wcsmbs/isoc99_vswscanf.c
+++ b/wcsmbs/isoc99_vswscanf.c
@@ -24,24 +24,16 @@
    This exception applies to code released by its copyright holders
    in files containing the exception.  */
 
-#include <libioP.h>
 #include <wchar.h>
-#include "../libio/strfile.h"
+#include <libio/strfile.h>
 
 int
 __isoc99_vswscanf (const wchar_t *string, const wchar_t *format, va_list args)
 {
-  int ret;
   _IO_strfile sf;
   struct _IO_wide_data wd;
-#ifdef _IO_MTSAFE_IO
-  sf._sbf._f._lock = NULL;
-#endif
-  _IO_no_init (&sf._sbf._f, _IO_USER_LOCK, 0, &wd, &_IO_wstr_jumps);
-  _IO_fwide (&sf._sbf._f, 1);
-  _IO_wstr_init_static (&sf._sbf._f, (wchar_t *)string, 0, NULL);
-  sf._sbf._f._flags2 |= _IO_FLAGS2_SCANF_STD;
-  ret = _IO_vfwscanf ((FILE *) &sf._sbf, format, args, NULL);
-  return ret;
+  FILE *f = _IO_strfile_readw (&sf, &wd, string);
+  f->_flags2 |= _IO_FLAGS2_SCANF_STD;
+  return __vfwscanf_internal (f, format, args, 0);
 }
 libc_hidden_def (__isoc99_vswscanf)
diff --git a/wcsmbs/isoc99_vwscanf.c b/wcsmbs/isoc99_vwscanf.c
index 049521b964..eb22c8acae 100644
--- a/wcsmbs/isoc99_vwscanf.c
+++ b/wcsmbs/isoc99_vwscanf.c
@@ -28,7 +28,7 @@ __isoc99_vwscanf (const wchar_t *format, va_list args)
 
   _IO_acquire_lock_clear_flags2 (stdin);
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
-  done = _IO_vfwscanf (stdin, format, args, NULL);
+  done = __vfwscanf_internal (stdin, format, args, 0);
   _IO_release_lock (stdin);
   return done;
 }
diff --git a/wcsmbs/isoc99_wscanf.c b/wcsmbs/isoc99_wscanf.c
index abfbd50c11..59f80d78fb 100644
--- a/wcsmbs/isoc99_wscanf.c
+++ b/wcsmbs/isoc99_wscanf.c
@@ -33,7 +33,7 @@ __isoc99_wscanf (const wchar_t *format, ...)
   stdin->_flags2 |= _IO_FLAGS2_SCANF_STD;
 
   va_start (arg, format);
-  done = _IO_vfwscanf (stdin, format, arg, NULL);
+  done = __vfwscanf_internal (stdin, format, arg, 0);
   va_end (arg);
 
   _IO_release_lock (stdin);
