]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
support: Add missing NSS formatting and checking functions
authorFlorian Weimer <fweimer@redhat.com>
Thu, 12 Feb 2026 11:18:54 +0000 (12:18 +0100)
committerFlorian Weimer <fweimer@redhat.com>
Thu, 12 Feb 2026 11:18:54 +0000 (12:18 +0100)
This change is largely auto-generated.  The function implementations
are mechanical and use the glibc-specific support framework, so this
should be low-risk and therefore acceptable.

The struct etherent type is currently internal-only (although it
can be used by NSS modules), which is why it is not included here.

Reviewed-by: DJ Delorie <dj@redhat.com>
22 files changed:
support/Makefile
support/check_aliasent.c [new file with mode: 0644]
support/check_ether_addr.c [new file with mode: 0644]
support/check_group.c [new file with mode: 0644]
support/check_nss.h
support/check_passwd.c [new file with mode: 0644]
support/check_protoent.c [new file with mode: 0644]
support/check_rpcent.c [new file with mode: 0644]
support/check_servent.c [new file with mode: 0644]
support/check_sgrp.c [new file with mode: 0644]
support/check_spwd.c [new file with mode: 0644]
support/format_nss.h
support/support_format_aliasent.c [new file with mode: 0644]
support/support_format_ether_addr.c [new file with mode: 0644]
support/support_format_group.c [new file with mode: 0644]
support/support_format_passwd.c [new file with mode: 0644]
support/support_format_protoent.c [new file with mode: 0644]
support/support_format_rpcent.c [new file with mode: 0644]
support/support_format_servent.c [new file with mode: 0644]
support/support_format_sgrp.c [new file with mode: 0644]
support/support_format_spwd.c [new file with mode: 0644]
support/tst-support_format_nss.c [new file with mode: 0644]

index 935503c9b3c4a2e33efbad1e9420fb93473e3506..5b59394274201d9b774a0569dbbeece79c7a0a93 100644 (file)
@@ -28,9 +28,18 @@ libsupport-routines = \
   blob_repeat \
   check \
   check_addrinfo \
+  check_aliasent \
   check_dns_packet \
+  check_ether_addr \
+  check_group \
   check_hostent \
   check_netent \
+  check_passwd \
+  check_protoent \
+  check_rpcent \
+  check_servent \
+  check_sgrp \
+  check_spwd \
   delayed_exit \
   dtotimespec \
   dtotimespec-time64 \
@@ -61,10 +70,19 @@ libsupport-routines = \
   support_enter_network_namespace \
   support_format_address_family \
   support_format_addrinfo \
+  support_format_aliasent \
   support_format_dns_packet \
+  support_format_ether_addr \
+  support_format_group \
   support_format_herrno \
   support_format_hostent \
   support_format_netent \
+  support_format_passwd \
+  support_format_protoent \
+  support_format_rpcent \
+  support_format_servent \
+  support_format_sgrp \
+  support_format_spwd \
   support_fuse \
   support_isolate_in_subprocess \
   support_mem_access \
@@ -359,6 +377,7 @@ tests = \
   tst-support_capture_subprocess \
   tst-support_descriptors \
   tst-support_format_dns_packet \
+  tst-support_format_nss \
   tst-support_fuse \
   tst-support_quote_blob \
   tst-support_quote_blob_wide \
diff --git a/support/check_aliasent.c b/support/check_aliasent.c
new file mode 100644 (file)
index 0000000..1545c3d
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct aliasent values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_aliasent (const char *description, const struct aliasent *e,
+                const char *expected)
+{
+  char *formatted = support_format_aliasent (e);
+  support_check_nss (description, "aliasent", formatted, expected);
+}
diff --git a/support/check_ether_addr.c b/support/check_ether_addr.c
new file mode 100644 (file)
index 0000000..f545ccd
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct ether_addr values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_ether_addr (const char *description, const struct ether_addr *e,
+                  const char *expected)
+{
+  char *formatted = support_format_ether_addr (e);
+  support_check_nss (description, "ether_addr", formatted, expected);
+}
diff --git a/support/check_group.c b/support/check_group.c
new file mode 100644 (file)
index 0000000..e58046d
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct group values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_group (const char *description, const struct group *g,
+             const char *expected)
+{
+  char *formatted = support_format_group (g);
+  support_check_nss (description, "group", formatted, expected);
+}
index 6bacb9978f6425b181f2ea213c94ff25f1c67a5d..66c291dc3b4a6296865ecf08171e28ef7103ac55 100644 (file)
 __BEGIN_DECLS
 
 struct addrinfo;
+struct aliasent;
+struct ether_addr;
+struct group;
 struct hostent;
 struct netent;
+struct passwd;
+struct protoent;
+struct rpcent;
+struct servent;
+struct sgrp;
+struct spwd;
 
 /* Compare the data structures against the expected values (which have
    to be formatted according to the support_format_* functions in
@@ -34,12 +43,30 @@ struct netent;
    failure is recorded, and a diff is written to standard output.  */
 void check_addrinfo (const char *query_description,
                      const struct addrinfo *, int ret, const char *expected);
+void check_aliasent (const char *description, const struct aliasent *,
+                     const char *expected);
 void check_dns_packet (const char *query_description,
                        const unsigned char *, size_t, const char *expected);
+void check_ether_addr (const char *description, const struct ether_addr *,
+                       const char *expected);
+void check_group (const char *description, const struct group *,
+                  const char *expected);
 void check_hostent (const char *query_description,
                     const struct hostent *, const char *expected);
 void check_netent (const char *query_description,
                    const struct netent *, const char *expected);
+void check_passwd (const char *description, const struct passwd *,
+                   const char *expected);
+void check_protoent (const char *description, const struct protoent *,
+                     const char *expected);
+void check_rpcent (const char *description, const struct rpcent *,
+                   const char *expected);
+void check_servent (const char *description, const struct servent *,
+                    const char *expected);
+void check_sgrp (const char *description, const struct sgrp *,
+                 const char *expected);
+void check_spwd (const char *description, const struct spwd *,
+                 const char *expected);
 
 /* Helper routine for implementing the functions above.  Report an
    error if ACTUAL and EXPECTED are not equal.  ACTUAL is always freed.  */
diff --git a/support/check_passwd.c b/support/check_passwd.c
new file mode 100644 (file)
index 0000000..d95864d
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct passwd values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_passwd (const char *description, const struct passwd *p,
+              const char *expected)
+{
+  char *formatted = support_format_passwd (p);
+  support_check_nss (description, "passwd", formatted, expected);
+}
diff --git a/support/check_protoent.c b/support/check_protoent.c
new file mode 100644 (file)
index 0000000..9ff1aac
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct protoent values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_protoent (const char *description, const struct protoent *e,
+                const char *expected)
+{
+  char *formatted = support_format_protoent (e);
+  support_check_nss (description, "protoent", formatted, expected);
+}
diff --git a/support/check_rpcent.c b/support/check_rpcent.c
new file mode 100644 (file)
index 0000000..df91351
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct rpcent values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_rpcent (const char *description, const struct rpcent *e,
+              const char *expected)
+{
+  char *formatted = support_format_rpcent (e);
+  support_check_nss (description, "rpcent", formatted, expected);
+}
diff --git a/support/check_servent.c b/support/check_servent.c
new file mode 100644 (file)
index 0000000..2281278
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct servent values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_servent (const char *description, const struct servent *e,
+               const char *expected)
+{
+  char *formatted = support_format_servent (e);
+  support_check_nss (description, "servent", formatted, expected);
+}
diff --git a/support/check_sgrp.c b/support/check_sgrp.c
new file mode 100644 (file)
index 0000000..592d7c9
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct sgrp values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_sgrp (const char *description, const struct sgrp *s,
+            const char *expected)
+{
+  char *formatted = support_format_sgrp (s);
+  support_check_nss (description, "sgrp", formatted, expected);
+}
diff --git a/support/check_spwd.c b/support/check_spwd.c
new file mode 100644 (file)
index 0000000..32c07e2
--- /dev/null
@@ -0,0 +1,29 @@
+/* Compare struct spwd values against a formatted string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check_nss.h>
+
+#include <support/format_nss.h>
+
+void
+check_spwd (const char *description, const struct spwd *s,
+            const char *expected)
+{
+  char *formatted = support_format_spwd (s);
+  support_check_nss (description, "spwd", formatted, expected);
+}
index a81658cfcbcaa1fdea7c3dd753cf242483977cf3..08d39f93d7d0e0ccd73a38f521c997bca3b8565a 100644 (file)
 __BEGIN_DECLS
 
 struct addrinfo;
+struct aliasent;
+struct ether_addr;
+struct group;
 struct hostent;
 struct netent;
+struct passwd;
+struct protoent;
+struct rpcent;
+struct servent;
+struct sgrp;
+struct spwd;
 
 /* The following functions format their arguments as human-readable
    strings (which can span multiple lines).  The caller must free the
@@ -35,10 +44,19 @@ struct netent;
    result.  */
 char *support_format_address_family (int);
 char *support_format_addrinfo (const struct addrinfo *, int ret);
+char *support_format_aliasent (const struct aliasent *);
 char *support_format_dns_packet (const unsigned char *buffer, size_t length);
+char *support_format_ether_addr (const struct ether_addr *);
+char *support_format_group (const struct group *);
 char *support_format_herrno (int);
 char *support_format_hostent (const struct hostent *);
 char *support_format_netent (const struct netent *);
+char *support_format_passwd (const struct passwd *);
+char *support_format_protoent (const struct protoent *);
+char *support_format_rpcent (const struct rpcent *);
+char *support_format_servent (const struct servent *);
+char *support_format_sgrp (const struct sgrp *);
+char *support_format_spwd (const struct spwd *);
 
 __END_DECLS
 
diff --git a/support/support_format_aliasent.c b/support/support_format_aliasent.c
new file mode 100644 (file)
index 0000000..25c180d
--- /dev/null
@@ -0,0 +1,42 @@
+/* Convert a struct aliasent object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <aliases.h>
+#include <errno.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_aliasent (const struct aliasent *e)
+{
+  if (e == NULL)
+    xasprintf ("errno: (errno %d, %m)\n", errno);
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "name: %s\n", e->alias_name);
+  for (size_t i = 0; i < e->alias_members_len; ++i)
+    fprintf (mem.out, "member: %s\n", e->alias_members[i]);
+  fprintf (mem.out, "local: %d\n", e->alias_local);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_ether_addr.c b/support/support_format_ether_addr.c
new file mode 100644 (file)
index 0000000..2cfe5f2
--- /dev/null
@@ -0,0 +1,33 @@
+/* Convert a struct ether_addr object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <errno.h>
+#include <netinet/ether.h>
+#include <support/support.h>
+
+char *
+support_format_ether_addr (const struct ether_addr *e)
+{
+  if (e == NULL)
+    return xasprintf ("error: (errno %d, %m)\n", errno);
+
+  char buf[sizeof ("xx:xx:xx:xx:xx:xx")];
+  return xasprintf ("address: %s\n", ether_ntoa_r (e, buf));
+}
diff --git a/support/support_format_group.c b/support/support_format_group.c
new file mode 100644 (file)
index 0000000..fb71456
--- /dev/null
@@ -0,0 +1,43 @@
+/* Convert a struct group object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <errno.h>
+#include <grp.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_group (const struct group *g)
+{
+  if (g == NULL)
+    return xasprintf ("error: (errno %d, %m)\n", errno);
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "name: %s\n", g->gr_name);
+  fprintf (mem.out, "passwd: %s\n", g->gr_passwd);
+  fprintf (mem.out, "gid: %u\n", (unsigned) g->gr_gid);
+  for (char **mp = g->gr_mem; *mp != NULL; ++mp)
+    fprintf (mem.out, "member: %s\n", *mp);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_passwd.c b/support/support_format_passwd.c
new file mode 100644 (file)
index 0000000..cf9fdef
--- /dev/null
@@ -0,0 +1,45 @@
+/* Convert a struct passwd object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <errno.h>
+#include <pwd.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_passwd (const struct passwd *p)
+{
+  if (p == NULL)
+    return xasprintf ("error: (errno %d, %m)\n", errno);
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "name: %s\n", p->pw_name);
+  fprintf (mem.out, "passwd: %s\n", p->pw_passwd);
+  fprintf (mem.out, "uid: %u\n", (unsigned int) p->pw_uid);
+  fprintf (mem.out, "gid: %u\n", (unsigned int) p->pw_gid);
+  fprintf (mem.out, "gecos: %s\n", p->pw_gecos);
+  fprintf (mem.out, "dir: %s\n", p->pw_dir);
+  fprintf (mem.out, "shell: %s\n", p->pw_shell);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_protoent.c b/support/support_format_protoent.c
new file mode 100644 (file)
index 0000000..25c177f
--- /dev/null
@@ -0,0 +1,42 @@
+/* Convert a struct protoent object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <errno.h>
+#include <netdb.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_protoent (const struct protoent *e)
+{
+  if (e == NULL)
+    return xasprintf ("error: (errno %d, %m)\n", errno);
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "name: %s\n", e->p_name);
+  for (char **ap = e->p_aliases; *ap != NULL; ++ap)
+    fprintf (mem.out, "alias: %s\n", *ap);
+  fprintf (mem.out, "proto: %d\n", e->p_proto);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_rpcent.c b/support/support_format_rpcent.c
new file mode 100644 (file)
index 0000000..1b898f3
--- /dev/null
@@ -0,0 +1,42 @@
+/* Convert a struct rpcent object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <errno.h>
+#include <rpc/netdb.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_rpcent (const struct rpcent *r)
+{
+  if (r == NULL)
+    return xasprintf ("error: (errno %d, %m)\n", errno);
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "name: %s\n", r->r_name);
+  fprintf (mem.out, "number: %d\n", r->r_number);
+  for (char **ap = r->r_aliases; *ap != NULL; ++ap)
+    fprintf (mem.out, "alias: %s\n", *ap);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_servent.c b/support/support_format_servent.c
new file mode 100644 (file)
index 0000000..fbe8138
--- /dev/null
@@ -0,0 +1,44 @@
+/* Convert a struct servent object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <netdb.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_servent (const struct servent *e)
+{
+  if (e == NULL)
+    return xasprintf ("error: (errno %d, %m)\n", errno);
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "name: %s\n", e->s_name);
+  for (char **ap = e->s_aliases; *ap != NULL; ++ap)
+    fprintf (mem.out, "alias: %s\n", *ap);
+  fprintf (mem.out, "port: %d\n", ntohs (e->s_port));
+  fprintf (mem.out, "proto: %s\n", e->s_proto);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_sgrp.c b/support/support_format_sgrp.c
new file mode 100644 (file)
index 0000000..d9b7d12
--- /dev/null
@@ -0,0 +1,44 @@
+/* Convert a struct sgrp object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <errno.h>
+#include <gshadow.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_sgrp (const struct sgrp *s)
+{
+  if (s == NULL)
+    return xasprintf ("error: (errno %d, %m)\n", errno);
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "name: %s\n", s->sg_namp);
+  fprintf (mem.out, "passwd: %s\n", s->sg_passwd);
+  for (char **ap = s->sg_adm; *ap != NULL; ++ap)
+    fprintf (mem.out, "admin: %s\n", *ap);
+  for (char **mp = s->sg_mem; *mp != NULL; ++mp)
+    fprintf (mem.out, "member: %s\n", *mp);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/support_format_spwd.c b/support/support_format_spwd.c
new file mode 100644 (file)
index 0000000..7d05e2b
--- /dev/null
@@ -0,0 +1,47 @@
+/* Convert a struct spwd object to a string.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/format_nss.h>
+
+#include <errno.h>
+#include <shadow.h>
+#include <support/support.h>
+#include <support/xmemstream.h>
+
+char *
+support_format_spwd (const struct spwd *s)
+{
+  if (s == NULL)
+    return xasprintf ("error: (errno %d, %m)\n", errno);
+
+  struct xmemstream mem;
+  xopen_memstream (&mem);
+
+  fprintf (mem.out, "sp_namp: %s\n", s->sp_namp);
+  fprintf (mem.out, "sp_pwdp: %s\n", s->sp_pwdp);
+  fprintf (mem.out, "sp_lstchg: %ld\n", s->sp_lstchg);
+  fprintf (mem.out, "sp_min: %ld\n", s->sp_min);
+  fprintf (mem.out, "sp_max: %ld\n", s->sp_max);
+  fprintf (mem.out, "sp_warn: %ld\n", s->sp_warn);
+  fprintf (mem.out, "sp_inact: %ld\n", s->sp_inact);
+  fprintf (mem.out, "sp_expire: %ld\n", s->sp_expire);
+  fprintf (mem.out, "sp_flag: %lu\n", s->sp_flag);
+
+  xfclose_memstream (&mem);
+  return mem.buffer;
+}
diff --git a/support/tst-support_format_nss.c b/support/tst-support_format_nss.c
new file mode 100644 (file)
index 0000000..f3163d8
--- /dev/null
@@ -0,0 +1,417 @@
+/* Tests for the support_format_* functions.
+   Copyright (C) 2026 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
+   <https://www.gnu.org/licenses/>.  */
+
+#include <support/check.h>
+#include <support/check_nss.h>
+#include <support/format_nss.h>
+
+#include <aliases.h>
+#include <arpa/inet.h>
+#include <grp.h>
+#include <gshadow.h>
+#include <netdb.h>
+#include <netinet/ether.h>
+#include <pwd.h>
+#include <rpc/netdb.h>
+#include <shadow.h>
+
+static void
+test_format_address_family (void)
+{
+  support_check_nss ("AF_INET", "address_family",
+                     support_format_address_family (AF_INET),
+                     "INET");
+  support_check_nss ("AF_INET6", "address_family",
+                     support_format_address_family (AF_INET6),
+                     "INET6");
+  support_check_nss ("AF_LOCAL", "address_family",
+                     support_format_address_family (AF_LOCAL),
+                     "LOCAL");
+  support_check_nss ("AF_UNSPEC", "address_family",
+                     support_format_address_family (AF_UNSPEC),
+                     "UNSPEC");
+  support_check_nss ("unknown family", "address_family",
+                     support_format_address_family (12345),
+                     "<unknown address family 12345>");
+}
+
+static void
+test_format_herrno (void)
+{
+  support_check_nss ("HOST_NOT_FOUND", "herrno",
+                     support_format_herrno (HOST_NOT_FOUND),
+                     "HOST_NOT_FOUND");
+  support_check_nss ("NO_ADDRESS", "herrno",
+                     support_format_herrno (NO_ADDRESS),
+                     "NO_ADDRESS");
+  support_check_nss ("NO_RECOVERY", "herrno",
+                     support_format_herrno (NO_RECOVERY),
+                     "NO_RECOVERY");
+  support_check_nss ("TRY_AGAIN", "herrno",
+                     support_format_herrno (TRY_AGAIN),
+                     "TRY_AGAIN");
+  support_check_nss ("invalid herrno", "herrno",
+                     support_format_herrno (12345),
+                     "<invalid h_errno value 12345>\n");
+}
+
+static void
+test_format_passwd (void)
+{
+  struct passwd p =
+    {
+      .pw_name = (char *) "testuser",
+      .pw_passwd = (char *) "x",
+      .pw_uid = 1000,
+      .pw_gid = 1000,
+      .pw_gecos = (char *) "Test User",
+      .pw_dir = (char *) "/home/testuser",
+      .pw_shell = (char *) "/bin/bash"
+    };
+  support_check_nss ("passwd", "passwd",
+                     support_format_passwd (&p),
+                     "name: testuser\n"
+                     "passwd: x\n"
+                     "uid: 1000\n"
+                     "gid: 1000\n"
+                     "gecos: Test User\n"
+                     "dir: /home/testuser\n"
+                     "shell: /bin/bash\n");
+}
+
+static void
+test_format_group (void)
+{
+  char *members[] = { (char *) "user1", (char *) "user2", NULL };
+  struct group g =
+    {
+      .gr_name = (char *) "testgroup",
+      .gr_passwd = (char *) "x",
+      .gr_gid = 100,
+      .gr_mem = members
+    };
+  support_check_nss ("group with members", "group",
+                     support_format_group (&g),
+                     "name: testgroup\n"
+                     "passwd: x\n"
+                     "gid: 100\n"
+                     "member: user1\n"
+                     "member: user2\n");
+
+  char *no_members[] = { NULL };
+  struct group g_empty =
+    {
+      .gr_name = (char *) "emptygroup",
+      .gr_passwd = (char *) "",
+      .gr_gid = 200,
+      .gr_mem = no_members
+    };
+  support_check_nss ("group without members", "group",
+                     support_format_group (&g_empty),
+                     "name: emptygroup\n"
+                     "passwd: \n"
+                     "gid: 200\n");
+}
+
+static void
+test_format_spwd (void)
+{
+  struct spwd s =
+    {
+      .sp_namp = (char *) "testuser",
+      .sp_pwdp = (char *) "$6$rounds=5000$hash",
+      .sp_lstchg = 19000,
+      .sp_min = 0,
+      .sp_max = 99999,
+      .sp_warn = 7,
+      .sp_inact = -1,
+      .sp_expire = -1,
+      .sp_flag = 0
+    };
+  support_check_nss ("spwd", "spwd",
+                     support_format_spwd (&s),
+                     "sp_namp: testuser\n"
+                     "sp_pwdp: $6$rounds=5000$hash\n"
+                     "sp_lstchg: 19000\n"
+                     "sp_min: 0\n"
+                     "sp_max: 99999\n"
+                     "sp_warn: 7\n"
+                     "sp_inact: -1\n"
+                     "sp_expire: -1\n"
+                     "sp_flag: 0\n");
+}
+
+static void
+test_format_sgrp (void)
+{
+  char *admins[] = { (char *) "admin1", NULL };
+  char *members[] = { (char *) "user1", (char *) "user2", NULL };
+  struct sgrp s =
+    {
+      .sg_namp = (char *) "testgroup",
+      .sg_passwd = (char *) "!",
+      .sg_adm = admins,
+      .sg_mem = members
+    };
+  support_check_nss ("sgrp", "sgrp",
+                     support_format_sgrp (&s),
+                     "name: testgroup\n"
+                     "passwd: !\n"
+                     "admin: admin1\n"
+                     "member: user1\n"
+                     "member: user2\n");
+
+  char *no_admins[] = { NULL };
+  char *no_members[] = { NULL };
+  struct sgrp s_empty =
+    {
+      .sg_namp = (char *) "emptygroup",
+      .sg_passwd = (char *) "",
+      .sg_adm = no_admins,
+      .sg_mem = no_members
+    };
+  support_check_nss ("sgrp empty", "sgrp",
+                     support_format_sgrp (&s_empty),
+                     "name: emptygroup\n"
+                     "passwd: \n");
+}
+
+static void
+test_format_protoent (void)
+{
+  char *aliases[] = { (char *) "ICMP", NULL };
+  struct protoent p =
+    {
+      .p_name = (char *) "icmp",
+      .p_aliases = aliases,
+      .p_proto = 1
+    };
+  support_check_nss ("protoent with alias", "protoent",
+                     support_format_protoent (&p),
+                     "name: icmp\n"
+                     "alias: ICMP\n"
+                     "proto: 1\n");
+
+  char *no_aliases[] = { NULL };
+  struct protoent p_no_alias =
+    {
+      .p_name = (char *) "tcp",
+      .p_aliases = no_aliases,
+      .p_proto = 6
+    };
+  support_check_nss ("protoent without alias", "protoent",
+                     support_format_protoent (&p_no_alias),
+                     "name: tcp\n"
+                     "proto: 6\n");
+}
+
+static void
+test_format_servent (void)
+{
+  char *aliases[] = { (char *) "WWW", (char *) "www-http", NULL };
+  struct servent s =
+    {
+      .s_name = (char *) "http",
+      .s_aliases = aliases,
+      .s_port = htons (80),
+      .s_proto = (char *) "tcp"
+    };
+  support_check_nss ("servent", "servent",
+                     support_format_servent (&s),
+                     "name: http\n"
+                     "alias: WWW\n"
+                     "alias: www-http\n"
+                     "port: 80\n"
+                     "proto: tcp\n");
+}
+
+static void
+test_format_rpcent (void)
+{
+  char *aliases[] = { (char *) "portmap", (char *) "sunrpc", NULL };
+  struct rpcent r =
+    {
+      .r_name = (char *) "portmapper",
+      .r_aliases = aliases,
+      .r_number = 100000
+    };
+  support_check_nss ("rpcent", "rpcent",
+                     support_format_rpcent (&r),
+                     "name: portmapper\n"
+                     "number: 100000\n"
+                     "alias: portmap\n"
+                     "alias: sunrpc\n");
+}
+
+static void
+test_format_aliasent (void)
+{
+  char *members[] =
+    { (char *) "user1@example.com", (char *) "user2@example.com" };
+  struct aliasent a =
+    {
+      .alias_name = (char *) "staff",
+      .alias_members_len = 2,
+      .alias_members = members,
+      .alias_local = 0
+    };
+  support_check_nss ("aliasent", "aliasent",
+                     support_format_aliasent (&a),
+                     "name: staff\n"
+                     "member: user1@example.com\n"
+                     "member: user2@example.com\n"
+                     "local: 0\n");
+}
+
+static void
+test_format_ether_addr (void)
+{
+  struct ether_addr e = { { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55 } };
+  support_check_nss ("ether_addr", "ether_addr",
+                     support_format_ether_addr (&e),
+                     "address: 0:11:22:33:44:55\n");
+}
+
+static void
+test_format_hostent (void)
+{
+  char addr1[4] = { 192, 0, 2, 1 };
+  char addr2[4] = { 192, 0, 2, 2 };
+  char *addr_list[] = { addr1, addr2, NULL };
+  char *aliases[] = { (char *) "www.example", NULL };
+  struct hostent h =
+    {
+      .h_name = (char *) "example.com",
+      .h_aliases = aliases,
+      .h_addrtype = AF_INET,
+      .h_length = 4,
+      .h_addr_list = addr_list
+    };
+  support_check_nss ("hostent IPv4", "hostent",
+                     support_format_hostent (&h),
+                     "name: example.com\n"
+                     "alias: www.example\n"
+                     "address: 192.0.2.1\n"
+                     "address: 192.0.2.2\n");
+
+  char addr6[16] = { 0x20, 0x01, 0x0d, 0xb8, 0, 0, 0, 0,
+                     0, 0, 0, 0, 0, 0, 0, 1 };
+  char *addr6_list[] = { addr6, NULL };
+  char *no_aliases[] = { NULL };
+  struct hostent h6 =
+    {
+      .h_name = (char *) "ipv6.example.com",
+      .h_aliases = no_aliases,
+      .h_addrtype = AF_INET6,
+      .h_length = 16,
+      .h_addr_list = addr6_list
+    };
+  support_check_nss ("hostent IPv6", "hostent",
+                     support_format_hostent (&h6),
+                     "name: ipv6.example.com\n"
+                     "address: 2001:db8::1\n");
+}
+
+static void
+test_format_netent (void)
+{
+  char *aliases[] = { (char *) "localnet", NULL };
+  struct netent n =
+    {
+      .n_name = (char *) "loopback",
+      .n_aliases = aliases,
+      .n_addrtype = AF_INET,
+      .n_net = 0x7f000000
+    };
+  support_check_nss ("netent", "netent",
+                     support_format_netent (&n),
+                     "name: loopback\n"
+                     "alias: localnet\n"
+                     "net: 0x7f000000\n");
+}
+
+static void
+test_format_addrinfo (void)
+{
+  /* Test successful result with IPv4 address.  */
+  struct sockaddr_in sin =
+    {
+      .sin_family = AF_INET,
+      .sin_port = htons (80),
+      .sin_addr = { htonl (0xc0000201) }  /* 192.0.2.1 */
+    };
+  struct addrinfo ai =
+    {
+      .ai_flags = 0,
+      .ai_family = AF_INET,
+      .ai_socktype = SOCK_STREAM,
+      .ai_protocol = IPPROTO_TCP,
+      .ai_addrlen = sizeof (sin),
+      .ai_addr = (struct sockaddr *) &sin,
+      .ai_canonname = NULL,
+      .ai_next = NULL
+    };
+  support_check_nss ("addrinfo IPv4 STREAM/TCP", "addrinfo",
+                     support_format_addrinfo (&ai, 0),
+                     "address: STREAM/TCP 192.0.2.1 80\n");
+
+  /* Test with canonname.  */
+  struct addrinfo ai_canon =
+    {
+      .ai_flags = AI_CANONNAME,
+      .ai_family = AF_INET,
+      .ai_socktype = SOCK_DGRAM,
+      .ai_protocol = IPPROTO_UDP,
+      .ai_addrlen = sizeof (sin),
+      .ai_addr = (struct sockaddr *) &sin,
+      .ai_canonname = (char *) "canonical.example.com",
+      .ai_next = NULL
+    };
+  support_check_nss ("addrinfo with canonname", "addrinfo",
+                     support_format_addrinfo (&ai_canon, 0),
+                     "flags: AI_CANONNAME\n"
+                     "canonname: canonical.example.com\n"
+                     "address: DGRAM/UDP 192.0.2.1 80\n");
+
+  /* Test error case.  */
+  support_check_nss ("addrinfo EAI_NONAME", "addrinfo",
+                     support_format_addrinfo (NULL, EAI_NONAME),
+                     "error: Name or service not known\n");
+}
+
+static int
+do_test (void)
+{
+  test_format_address_family ();
+  test_format_herrno ();
+  test_format_passwd ();
+  test_format_group ();
+  test_format_spwd ();
+  test_format_sgrp ();
+  test_format_protoent ();
+  test_format_servent ();
+  test_format_rpcent ();
+  test_format_aliasent ();
+  test_format_ether_addr ();
+  test_format_hostent ();
+  test_format_netent ();
+  test_format_addrinfo ();
+  return 0;
+}
+
+#include <support/test-driver.c>