On Sat, Dec 06, 2008 at 04:20:45PM +0200, John Tytgat wrote:
> In message <[email protected]>
>           Theo Markettos <[email protected]> wrote:
> 
> > Anyway, attached is a patch to provide getgrouplist() for review.
>
> I would break out this getgrouplist() implementation into a new file in
> grp directory.  When you would do that, add something like this:

I've made most of the changes you suggested - new patch attached.

> > +  while ((grp = getgrent ()) !=NULL)
> > +    {
> > +      char **mem;
> 
> const char ** would be slightly better.

That doesn't work, because we have to modify the value of mem.

> What about doing a #include "../../grp/getgrouplist.c" instead (assuming you
> have your getgrouplist implementation in a separate file) and have the
> differences between this version and the UnixLib implementation covered with
> a test on __riscos ? So that we're sure that any changes in
> libunixlib/grp/getgrouplist.c are under test when compiling and running
> libunixlib/test/grp/getgrouplist.c ?

That's a good idea - I've done this.

Theo
Index: gcc4/recipe/files/libunixlib/grp/getgrouplist.c
===================================================================
--- gcc4/recipe/files/libunixlib/grp/getgrouplist.c	(revision 0)
+++ gcc4/recipe/files/libunixlib/grp/getgrouplist.c	(revision 0)
@@ -0,0 +1,133 @@
+/* getgrouplist ()
+ * Copyright (c) 2008 UnixLib Developers
+ * Written by Theo Markettos.
+ */
+
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <grp.h>
+#include <pthread.h>
+
+/* enable this to be built on a non-RISC OS system to test */
+#ifndef __riscos
+#define __set_errno(x) x
+#else
+#include <internal/unix.h>
+#endif
+
+
+/* getgrouplist():
+
+Standard:
+http://refspecs.freestandards.org/LSB_3.1.0/LSB-Core-generic/LSB-Core-generic/baselib-getgrouplist-3.html
+Quote:
+
+Description 
+
+The getgrouplist() function shall fill in the array groups with the
+supplementary groups for the user specified by user. On entry, ngroups shall
+refer to an integer containing the maximum number of gid_t members in the
+groups array. The group group shall also be included. On success, the value
+referred to by ngroups shall be updated to contain the number of gid_t
+objects copied.
+
+Return Value
+
+On success, if there was sufficient room to copy all the supplementatry
+group identifiers to the array identified by groups, getgrouplist() shall
+return the number of gid_t objects copied, and the value referenced by
+ngroups shall be updated. If there was not sufficient room to copy all the
+supplementary group identifiers, getgrouplist() shall return -1, and update the
+value referenced by ngroups to the number actually copied.
+
+If user does not refer to a valid user on the system, getgrouplist() shall
+return 0, and set the value referenced by ngroups to 0
+
+*/
+
+
+int
+getgrouplist (const char *user, gid_t group, gid_t *groups, int *ngroups)
+{
+  struct group *grp;
+  int grps_copied=0;
+  int moretocome=0;
+
+#ifdef __riscos
+  PTHREAD_UNSAFE_CANCELLATION
+#else
+  FILE *f;
+#endif  
+  /* Need a group name to lookup */
+  if (user == NULL)
+    return __set_errno (EINVAL);
+
+  /* And somewhere to store the results */
+  if (groups == NULL)
+    return __set_errno (EINVAL);
+
+  if (ngroups == NULL)
+    return __set_errno (EINVAL);
+
+  /* Need space to copy in at least one group ID */
+  if (*ngroups <= 0)
+    return __set_errno (EINVAL);
+
+#ifndef __riscos
+/* If building on a non-RISC OS system, use fgetgrent so we can read a test group file */
+  f=fopen("test.group","r");
+
+  if (!f) { fprintf(stderr,"Can't file group file test.group\n");abort();}
+#endif
+
+  /* Iterate through the group structure, copying gids of groups
+   * we find that match.  Leave at least one space at the end.
+   */
+#ifdef __riscos
+  while ((grp = getgrent ()) !=NULL)
+#else
+  while (( (grp = fgetgrent(f))!=NULL) )
+#endif
+    {
+      char **mem;
+
+      for (mem = grp->gr_mem;
+	   *mem && grps_copied < *ngroups;
+           ++mem)
+        {
+          if ((strcmp (*mem, user) == 0) && (grp->gr_gid!=group))
+          {  
+            if ((grps_copied+1) < (*ngroups))
+              groups[grps_copied++] = grp->gr_gid;
+            else
+              moretocome++;
+          }
+        }
+    }
+  endgrent ();
+  
+  /* if we failed to find this group anywhere, then indicate that */
+  if (grps_copied==0)
+  {
+    *ngroups=0;
+    return 0;
+  }
+  
+  /* tag on to the end the group we were told to add */
+  groups[grps_copied++] = group;
+
+  /* Return the number we copied */
+  *ngroups = grps_copied;
+
+  /* Return -1 if there are still more to copy */
+  if (moretocome)
+    return -1;
+
+  /* We succeeded, so return the number of groups we did find */
+  return grps_copied;
+}
+
Index: gcc4/recipe/files/libunixlib/test/grp/getgrouplist.c
===================================================================
--- gcc4/recipe/files/libunixlib/test/grp/getgrouplist.c	(revision 0)
+++ gcc4/recipe/files/libunixlib/test/grp/getgrouplist.c	(revision 0)
@@ -0,0 +1,116 @@
+/*
+ * Test function for getgrouplist()
+ *
+ * If built for RISC OS, will use the group file in /etc/group:
+ * need to copy the file test.groups there before running the test
+ * (and probably replace it afterwards with what was there before)
+ *
+ * If built for other platforms it'll use the host C library functions to
+ * read the file 'test.group' in the current directory.  It'll only test
+ * the copy of getgrouplist() found in this file, not the one in
+ * the main UnixLib tree.
+ *
+ * Copyright (c) 2008 UnixLib Developers
+ */
+
+/* if not on RISC OS include our own copy of the function */
+#ifndef __riscos
+#include "../../grp/getgrouplist.c"
+#else
+#include <errno.h>
+#include <limits.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <grp.h>
+#include <pthread.h>
+#endif
+
+#define IN(a,b,c,d) printf("Calling getgrouplist(\"%s\",%d,%x,%x) ",a,b,c,d);\
+if (d) printf(" ngroups=%d ",*d);
+#define OUT(r) printf(" result=%d ",r);
+#define GETGROUPLIST(a,b,c,d,e) IN(a,b,c,d);e=getgrouplist(a,b,c,d);OUT(e)
+#define TEST(a,b,f) {if(a==b) printf(" PASS! Expected %s=%s\n",#a,#b); else {printf(" FAIL! Expected %s=%s!\n",#a,#b);f=1;}}
+#define SHOWGROUPS(grps,ngrps) { int i=0; for (i=0; i<ngrps; i++) {printf("GID %d = %d\n",i,grps[i]);}}
+
+int main(void)
+{
+  char *user=NULL;
+  gid_t group=0;
+  gid_t groups[100];
+  int ngroups;
+  int result=0;
+  int *n=NULL;
+  int fail=0;
+
+/* these tests won't work unless you have the right group file in place - see above */
+#ifdef __riscos
+  fprintf(stderr,"libunixlib/test/grp/getgrouplist.c will only work if you have\n"\
+  "copied in libunixlib/test/grp/test.group into /etc/group on RISC OS.\n" \
+  "Make sure you restore /etc/group afterwards.\n");
+#endif
+  
+  GETGROUPLIST(user,group,n,n,result);
+  TEST(result,EINVAL,fail)
+  
+  GETGROUPLIST(user,group,groups,n,result);
+  TEST(result,EINVAL,fail);
+    
+  user="zzzz";
+  GETGROUPLIST(user,group,groups,n,result);
+  TEST(result,EINVAL,fail);
+
+  ngroups=0;
+  GETGROUPLIST(user,group,groups,&ngroups,result);
+  TEST(result,EINVAL,fail);
+
+  ngroups=3;
+  user="missing";
+  GETGROUPLIST(user,group,groups,&ngroups,result);
+  TEST(result,0,fail);
+  TEST(ngroups,0,fail);
+
+  ngroups=3;
+  user="bill";
+  group=(gid_t) 123;
+  GETGROUPLIST(user,group,groups,&ngroups,result);
+  TEST(result,-1,fail);
+  TEST(ngroups,3,fail);
+  SHOWGROUPS(groups,ngroups);  
+
+  ngroups=3;
+  user="fred";
+  group=(gid_t) 123;
+  GETGROUPLIST(user,group,groups,&ngroups,result);
+  TEST(result,3,fail);
+  TEST(ngroups,3,fail);
+  SHOWGROUPS(groups,ngroups);  
+
+  ngroups=20;
+  user="bill";
+  group=(gid_t) 123;
+  GETGROUPLIST(user,group,groups,&ngroups,result);
+  TEST(result,6,fail);
+  TEST(ngroups,6,fail);
+  SHOWGROUPS(groups,ngroups);  
+
+  ngroups=20;
+  user="bill";
+  group=(gid_t) 44;
+  GETGROUPLIST(user,group,groups,&ngroups,result);
+  TEST(result,5,fail);
+  TEST(ngroups,5,fail);
+  SHOWGROUPS(groups,ngroups);  
+
+  ngroups=5;
+  user="bill";
+  group=(gid_t) 44;
+  GETGROUPLIST(user,group,groups,&ngroups,result);
+  TEST(result,5,fail);
+  TEST(ngroups,5,fail);
+  SHOWGROUPS(groups,ngroups);  
+
+  return fail;
+}
+
Index: gcc4/recipe/files/libunixlib/test/grp/test.group
===================================================================
--- gcc4/recipe/files/libunixlib/test/grp/test.group	(revision 0)
+++ gcc4/recipe/files/libunixlib/test/grp/test.group	(revision 0)
@@ -0,0 +1,54 @@
+root:x:0:
+daemon:x:1:
+bin:x:2:
+sys:x:3:
+adm:x:4:
+tty:x:5:
+disk:x:6:
+lp:x:7:lp
+mail:x:8:
+news:x:9:
+uucp:x:10:
+proxy:x:13:
+kmem:x:15:
+dialout:x:20:
+fax:x:21:
+voice:x:22:
+cdrom:x:24:dave
+floppy:x:25:
+tape:x:26:smith,tony,dave,bill,mike
+sudo:x:27:
+audio:x:29:dave
+dip:x:30:tony
+postgres:x:32:jones
+www-data:x:33:
+backup:x:34:
+operator:x:37:
+list:x:38:
+irc:x:39:
+src:x:40:dave
+gnats:x:41:
+shadow:x:42:
+utmp:x:43:bill
+video:x:44:bill
+staff:x:50:bill
+games:x:60:
+scanner:x:70:dave
+users:x:100:
+nogroup:x:65534:
+dave:x:1000:
+lpadmin:x:101:
+man:*:12:
+sasl:*:45:
+crontab:x:102:
+ssh:x:103:
+camera:x:105:dave
+plugdev:*:46:
+Debian-exim:x:107:
+webadmin:x:1001:dave,www-data,fred
+mysql:x:108:bill
+archive:x:1003:archive,dave
+messagebus:x:109:
+fuse:x:110:dave
+ssl-cert:x:113:postgres
+ARMBOOT:x:1006:fred
Index: gcc4/recipe/files/libunixlib/include/grp.h
===================================================================
--- gcc4/recipe/files/libunixlib/include/grp.h	(revision 3564)
+++ gcc4/recipe/files/libunixlib/include/grp.h	(working copy)
@@ -109,6 +109,12 @@
    This function is a cancellation point.  */
 extern int initgroups (const char *__name, gid_t __basegid)
      __nonnull ((1));
+
+/* Return a list of groups the user is in */
+extern int getgrouplist (const char *__user, gid_t __group,
+    gid_t *__groups, int *__ngroups);
+     __nonnull ((1,3,4));
+
 #endif
 
 __END_DECLS
_______________________________________________
GCCSDK mailing list [email protected]
Bugzilla: http://www.riscos.info/bugzilla/index.cgi
List Info: http://www.riscos.info/mailman/listinfo/gcc
Main Page: http://www.riscos.info/index.php/GCCSDK

Reply via email to