This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC][PATCH] Add new getgrgid2(), getgrnam2() interfaces to glibc


This RFC patch adds support for new interfaces: getgrgid2(),
getgrnam2() and their *_r() variants. These interfaces allow
the user to specify whether the group.gr_mem field shall be
filled in.

The issue we are trying to solve is that needlessly high load is
generated in large deployments with NIS/LDAP user groups with possibly
thousands of members. Even when nscd is used, the information is
requested and transferred frequently even when there never arises
any real use for the huge lists of members at the node at all.

We have looked at some commonly used applications and e.g. for a normal
desktop, if some basic utilities and file managers would be trivially
modified to use the new interface, the full lists of users in a group
would never have to be downloaded. Right now, even ls will trigger
getting full lists of users in all groups it encounters. Moreover, e.g.
the sssd guys are reportedly trying to solve this problem by evil hacks
like randomly not filling or only partially filling the gr_mem field.

Any comments on the API are welcome, including thoughts on how to
make it more elegant. Originally, I wanted to implement it as
gid_t getgidbyname(const char *name) etc., but I would have to redo
some parts of the NSS infrastructure to easily allow returning gid_t
instead of a struct.

If there is a consensus that this is a good idea and Ulrich gives his
blessing, I will of course extend the patch to be compatible with older
NSS modules and add NIS support and nscd support.


diff --git a/grp/Makefile b/grp/Makefile
index e6ca864..43ec003 100644
--- a/grp/Makefile
+++ b/grp/Makefile
@@ -25,8 +25,9 @@ headers := grp.h
 distribute := tst_fgetgrent.c tst_fgetgrent.sh compat-initgroups.c
 
 routines := fgetgrent initgroups setgroups \
-	    getgrent getgrgid getgrnam putgrent \
-	    getgrent_r getgrgid_r getgrnam_r fgetgrent_r
+	    getgrent getgrgid getgrgid2 getgrnam getgrnam2 putgrent \
+	    getgrent_r getgrgid_r getgrgid2_r getgrnam_r getgrnam2_r \
+	    fgetgrent_r
 
 include ../Makeconfig
 
diff --git a/grp/Versions b/grp/Versions
index e01360d..63cafb4 100644
--- a/grp/Versions
+++ b/grp/Versions
@@ -28,4 +28,7 @@ libc {
     # g*
     getgrouplist;
   }
+  GLIBC_2.13 {
+    getgrgid2; getgrgid2_r; getgrnam2; getgrnam2_r;
+  }
 }
diff --git a/grp/grp.h b/grp/grp.h
index c06ef03..3a4711c 100644
--- a/grp/grp.h
+++ b/grp/grp.h
@@ -173,6 +173,39 @@ extern int fgetgrent_r (FILE *__restrict __stream,
 #endif	/* POSIX or reentrant */
 
 
+#ifdef __USE_GNU
+/* Search for an entry with a matching group ID.
+
+   This function is a possible cancellation point and therefore not
+   marked with __THROW.  */
+extern struct group *getgrgid2 (__gid_t __gid, int want_members);
+
+/* Search for an entry with a matching group name.
+
+   This function is a possible cancellation point and therefore not
+   marked with __THROW.  */
+extern struct group *getgrnam2 (__const char *__name, int want_members);
+
+/* Search for an entry with a matching group ID.
+
+   This function is a possible cancellation point and therefore not
+   marked with __THROW.  */
+extern int getgrgid2_r (__gid_t __gid, int want_members,
+			struct group *__restrict __resultbuf,
+			char *__restrict __buffer, size_t __buflen,
+			struct group **__restrict __result);
+
+/* Search for an entry with a matching group name.
+
+   This function is a possible cancellation point and therefore not
+   marked with __THROW.  */
+extern int getgrnam2_r (__const char *__restrict __name, int want_members,
+			struct group *__restrict __resultbuf,
+			char *__restrict __buffer, size_t __buflen,
+			struct group **__restrict __result);
+#endif
+
+
 #ifdef	__USE_BSD
 
 # define __need_size_t
diff --git a/include/grp.h b/include/grp.h
index 5ed9c97..986855c 100644
--- a/include/grp.h
+++ b/include/grp.h
@@ -20,6 +20,10 @@ extern int __getgrgid_r (__gid_t __gid, struct group *__resultbuf,
 extern int __old_getgrgid_r (__gid_t __gid, struct group *__resultbuf,
 			     char *__buffer, size_t __buflen,
 			     struct group **__result);
+extern int __getgrgid2_r (__gid_t __gid, int want_members,
+			 struct group *__resultbuf,
+			 char *__buffer, size_t __buflen,
+			 struct group **__result);
 
 /* Search for an entry with a matching group name.  */
 extern int __getgrnam_r (__const char *__name, struct group *__resultbuf,
@@ -28,6 +32,10 @@ extern int __getgrnam_r (__const char *__name, struct group *__resultbuf,
 extern int __old_getgrnam_r (__const char *__name, struct group *__resultbuf,
 			     char *__buffer, size_t __buflen,
 			     struct group **__result);
+extern int __getgrnam2_r (__const char *__name, int want_members,
+			 struct group *__resultbuf,
+			 char *__buffer, size_t __buflen,
+			 struct group **__result);
 
 struct parser_data;
 extern int _nss_files_parse_grent (char *line, struct group *result,
@@ -41,9 +49,16 @@ extern enum nss_status _nss_ ## service ## _endgrent (void);		   \
 extern enum nss_status _nss_ ## service ## _getgrgid_r			   \
                        (gid_t gid, struct group *grp, char *buffer,	   \
 			size_t buflen, int *errnop);			   \
+extern enum nss_status _nss_ ## service ## _getgrgid2_r			   \
+                       (gid_t gid, int want_members, struct group *grp,	   \
+			char *buffer, size_t buflen, int *errnop);	   \
 extern enum nss_status _nss_ ## service ## _getgrnam_r			   \
                        (const char *name, struct group *grp,		   \
 			char *buffer, size_t buflen, int *errnop);	   \
+extern enum nss_status _nss_ ## service ## _getgrnam2_r			   \
+                       (const char *name, int want_members,		   \
+			struct group *grp, char *buffer, size_t buflen,	   \
+			int *errnop);					   \
 extern enum nss_status _nss_ ## service ##_getgrent_r			   \
                        (struct group *result, char *buffer, size_t buflen, \
 			int *errnop);					   \
diff --git a/manual/users.texi b/manual/users.texi
index b52ee44..a3c995b 100644
--- a/manual/users.texi
+++ b/manual/users.texi
@@ -1745,7 +1745,8 @@ null pointer.
 @cindex converting group ID to group name
 
 You can search the group database for information about a specific
-group using @code{getgrgid} or @code{getgrnam}.  These functions are
+group using @code{getgrgid2} and @code{getgrnam2} (or their portable
+versions @code{getgrgid} and @code{getgrnam}).  These functions are
 declared in @file{grp.h}.
 
 @comment grp.h
@@ -1760,6 +1761,18 @@ A null pointer indicates there is no group with ID @var{gid}.
 @end deftypefun
 
 @comment grp.h
+@deftypefun {struct group *} getgrgid2 (gid_t @var{gid}, int want_members)
+This function is similar to @code{getgrgid} in that it returns
+information about the group whose group ID is @var{gid}. However,
+if 1 is passed as the @var{want_members} parameter, the
+@code{group.gr_mem} field may be left unset and the application
+should not rely on its contents. If the application does not need
+the full list of group members, this is the preferred mode of
+operation. It is much more efficient in case of large network
+groups.
+@end deftypefun
+
+@comment grp.h
 @comment POSIX.1c
 @deftypefun int getgrgid_r (gid_t @var{gid}, struct group *@var{result_buf}, char *@var{buffer}, size_t @var{buflen}, struct group **@var{result})
 This function is similar to @code{getgrgid} in that it returns
@@ -1781,6 +1794,12 @@ error code @code{ERANGE} is returned and @var{errno} is set to
 @end deftypefun
 
 @comment grp.h
+@deftypefun {struct group *} getgrgid2_r (gid_t @var{gid}, int want_members, struct group *@var{result_buf}, char *@var{buffer}, size_t @var{buflen}, struct group **@var{result})
+This function is similar to @code{getgrgid_r}, but takes an extra
+argument @var{want_members} that is interpreted like in @code{getgrgid2}.
+@end deftypefun
+
+@comment grp.h
 @comment SVID, BSD
 @deftypefun {struct group *} getgrnam (const char *@var{name})
 This function returns a pointer to a statically-allocated structure
@@ -1792,6 +1811,18 @@ A null pointer indicates there is no group named @var{name}.
 @end deftypefun
 
 @comment grp.h
+@deftypefun {struct group *} getgrnam2 (const char *@var{name}, int want_members)
+This function is similar to @code{getgrnam} in that it returns
+information about the group whose group name is @var{name}.
+However, if 1 is passed as the @var{want_members} parameter, the
+@code{group.gr_mem} field may be left unset and the application
+should not rely on its contents. If the application does not need
+the full list of group members, this is the preferred mode of
+operation. It is much more efficient in case of large network
+groups.
+@end deftypefun
+
+@comment grp.h
 @comment POSIX.1c
 @deftypefun int getgrnam_r (const char *@var{name}, struct group *@var{result_buf}, char *@var{buffer}, size_t @var{buflen}, struct group **@var{result})
 This function is similar to @code{getgrnam} in that is returns
@@ -1803,6 +1834,12 @@ The return values are the same as for @code{getgrgid_r}
 @code{ERANGE}.
 @end deftypefun
 
+@comment grp.h
+@deftypefun {struct group *} getgrnam2_r (const char *@var{name}, int want_members, struct group *@var{result_buf}, char *@var{buffer}, size_t @var{buflen}, struct group **@var{result})
+This function is similar to @code{getgrnam_r}, but takes an extra
+argument @var{want_members} that is interpreted like in @code{getgrnam2}.
+@end deftypefun
+
 @node Scanning All Groups
 @subsection Scanning the List of All Groups
 @cindex scanning the group list
diff --git a/nss/Versions b/nss/Versions
index 7a9d67b..9650c78 100644
--- a/nss/Versions
+++ b/nss/Versions
@@ -32,7 +32,9 @@ libnss_files {
     _nss_files_endgrent;
     _nss_files_getgrent_r;
     _nss_files_getgrgid_r;
+    _nss_files_getgrgid2_r;
     _nss_files_getgrnam_r;
+    _nss_files_getgrnam2_r;
 
     _nss_files_sethostent;
     _nss_files_endhostent;
diff --git a/nss/function.def b/nss/function.def
index 505fb93..fabbf2f 100644
--- a/nss/function.def
+++ b/nss/function.def
@@ -31,7 +31,9 @@ DEFINE_ENT (files, ether)
 /* group */
 DEFINE_ENT (files, gr)
 DEFINE_GET (files, grgid)
+DEFINE_GET (files, grgid2)
 DEFINE_GET (files, grnam)
+DEFINE_GET (files, grnam2)
 
 /* hosts */
 DEFINE_ENT (files, host)
diff --git a/nss/nss_files/files-grp.c b/nss/nss_files/files-grp.c
index 1f205c1..f0ec72b 100644
--- a/nss/nss_files/files-grp.c
+++ b/nss/nss_files/files-grp.c
@@ -37,9 +37,23 @@ DB_LOOKUP (grnam, 1 + strlen (name), (".%s", name),
 	       break;
 	   }, const char *name)
 
+DB_LOOKUP (grnam2, 1 + strlen (name), (".%s", name),
+	   {
+	     if (name[0] != '-' && name[0] != '+'
+		 && ! strcmp (name, result->gr_name))
+	       break;
+	   }, const char *name, int want_members)
+
 DB_LOOKUP (grgid, 20, ("=%lu", (unsigned long int) gid),
 	   {
 	     if (result->gr_gid == gid && result->gr_name[0] != '+'
 		 && result->gr_name[0] != '-')
 	       break;
 	   }, gid_t gid)
+
+DB_LOOKUP (grgid2, 20, ("=%lu", (unsigned long int) gid),
+	   {
+	     if (result->gr_gid == gid && result->gr_name[0] != '+'
+		 && result->gr_name[0] != '-')
+	       break;
+	   }, gid_t gid, int want_members)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]