This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
reentr.c: Handle getspnam()
authorKarl Williamson <khw@cpan.org>
Wed, 11 Mar 2020 18:24:33 +0000 (12:24 -0600)
committerKarl Williamson <khw@cpan.org>
Wed, 18 Mar 2020 20:29:46 +0000 (14:29 -0600)
This has never worked to increase the buffer size if necessary.
Apparently the default has always been big enough.  But this commit
fixes it to retry if too small.

I don't think there is a way to write tests for this.  getspnam is
called only as a small part of pp_gpwent, and is not part of the API,
and is called only when run as root.

I did test it on my box, with gdb, starting with a buffer size of 1, and
single stepping and observing that it works as I expected.

reentr.c
reentr.h
regen/reentr.pl

index ede96a9..10c2d88 100644 (file)
--- a/reentr.c
+++ b/reentr.c
@@ -381,6 +381,16 @@ Perl_reentrant_retry(const char *f, ...)
 #endif
 
     if (key == 0) {
+
+#ifdef HAS_GETSPNAM_R
+
+       /* This is a #define as has no corresponding keyword */
+        if (strEQ(f, "getspnam")) {
+            key = KEY_getspnam;
+        }
+
+#endif
+
     }
     else if (key < 0) {
         key = -key;
@@ -510,9 +520,9 @@ Perl_reentrant_retry(const char *f, ...)
 #  endif
 #  ifdef USE_PWENT_BUFFER
 
-    case KEY_getpwnam:
-    case KEY_getpwuid:
-    case KEY_getpwent:
+    case  KEY_getpwnam:
+    case  KEY_getpwuid:
+    case  KEY_getpwent:
        {
 
 #    ifdef PERL_REENTRANT_MAXSIZE
@@ -551,6 +561,31 @@ Perl_reentrant_retry(const char *f, ...)
        break;
 
 #  endif
+#  ifdef USE_SPENT_BUFFER
+
+    case KEY_getspnam:
+       {
+            char * name;
+
+#    ifdef PERL_REENTRANT_MAXSIZE
+           if (PL_reentrant_buffer->_spent_size <=
+               PERL_REENTRANT_MAXSIZE / 2)
+
+#    endif
+            RenewDouble(PL_reentrant_buffer->_spent_buffer,
+                    &PL_reentrant_buffer->_spent_size, char);
+            switch (key) {
+               case KEY_getspnam:
+                   name = va_arg(ap, char *);
+                   retptr = getspnam(name); break;
+               default:
+                   SETERRNO(ERANGE, LIB_INVARG);
+                   break;
+            }
+       }
+       break;
+
+#  endif
 #  ifdef USE_PROTOENT_BUFFER
 
     case KEY_getprotobyname:
index 9e65001..25f21ad 100644 (file)
--- a/reentr.h
+++ b/reentr.h
 #    undef  USE_PWENT_BUFFER
 #  endif
 
+/* The getspent getspnam using buffer? */
+
+#  if defined(HAS_GETSPNAM_R) && (GETSPNAM_R_PROTO == REENTRANT_PROTO_I_CSBWR || GETSPNAM_R_PROTO == REENTRANT_PROTO_S_CSBI)
+#    define GETSPNAM_R_HAS_BUFFER
+#  else
+#    undef  GETSPNAM_R_HAS_BUFFER
+#  endif
+
+/* Any of the getspent getspnam using buffer? */
+
+#  if (defined(GETSPENT_R_HAS_BUFFER) || defined(GETSPNAM_R_HAS_BUFFER))
+#    define USE_SPENT_BUFFER
+#  else
+#    undef  USE_SPENT_BUFFER
+#  endif
+
 /* The gethostent gethostbyaddr gethostbyname using ptr? */
 
 #  if defined(HAS_GETHOSTENT_R) && (GETHOSTENT_R_PROTO == REENTRANT_PROTO_I_SBWRE)
@@ -1495,6 +1511,12 @@ typedef struct {
 
 
 
+
+/* Special case this; if others came along, could automate it */
+#  ifdef HAS_GETSPNAM_R
+#    define KEY_getspnam -1
+#  endif
+
 #endif /* USE_REENTRANT_API */
 
 #endif
index 5fe887d..e672bb5 100644 (file)
@@ -434,6 +434,9 @@ define('FPTR', 'H',
 define('BUFFER',  'B',
        qw(getpwent getpwgid getpwnam));
 
+define('BUFFER',  'B',
+       qw(getspent getspnam));
+
 define('PTR', 'R',
        qw(gethostent gethostbyaddr gethostbyname));
 define('PTR', 'R',
@@ -739,6 +742,12 @@ typedef struct {
 /* The wrappers. */
 
 @wrap
+
+/* Special case this; if others came along, could automate it */
+#  ifdef HAS_GETSPNAM_R
+#    define KEY_getspnam -1
+#  endif
+
 #endif /* USE_REENTRANT_API */
 
 #endif
@@ -860,6 +869,16 @@ Perl_reentrant_retry(const char *f, ...)
 #endif
 
     if (key == 0) {
+
+#ifdef HAS_GETSPNAM_R
+
+       /* This is a #define as has no corresponding keyword */
+        if (strEQ(f, "getspnam")) {
+            key = KEY_getspnam;
+        }
+
+#endif
+
     }
     else if (key < 0) {
         key = -key;
@@ -989,9 +1008,9 @@ Perl_reentrant_retry(const char *f, ...)
 #  endif
 #  ifdef USE_PWENT_BUFFER
 
-    case KEY_getpwnam:
-    case KEY_getpwuid:
-    case KEY_getpwent:
+    case  KEY_getpwnam:
+    case  KEY_getpwuid:
+    case  KEY_getpwent:
        {
 
 #    ifdef PERL_REENTRANT_MAXSIZE
@@ -1030,6 +1049,31 @@ Perl_reentrant_retry(const char *f, ...)
        break;
 
 #  endif
+#  ifdef USE_SPENT_BUFFER
+
+    case KEY_getspnam:
+       {
+            char * name;
+
+#    ifdef PERL_REENTRANT_MAXSIZE
+           if (PL_reentrant_buffer->_spent_size <=
+               PERL_REENTRANT_MAXSIZE / 2)
+
+#    endif
+            RenewDouble(PL_reentrant_buffer->_spent_buffer,
+                    &PL_reentrant_buffer->_spent_size, char);
+            switch (key) {
+               case KEY_getspnam:
+                   name = va_arg(ap, char *);
+                   retptr = getspnam(name); break;
+               default:
+                   SETERRNO(ERANGE, LIB_INVARG);
+                   break;
+            }
+       }
+       break;
+
+#  endif
 #  ifdef USE_PROTOENT_BUFFER
 
     case KEY_getprotobyname: