bb_getgroups.c 1.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
  1. /*
  2. * Utility routines.
  3. *
  4. * Copyright (C) 2017 Denys Vlasenko
  5. *
  6. * Licensed under GPLv2, see file LICENSE in this source tree.
  7. */
  8. //kbuild:lib-y += bb_getgroups.o
  9. #include "libbb.h"
  10. gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array)
  11. {
  12. int n = ngroups ? *ngroups : 0;
  13. /* getgroups may be a bit expensive, try to use it only once */
  14. if (n < 32)
  15. n = 32;
  16. for (;;) {
  17. // FIXME: ash tries so hard to not die on OOM (when we are called from test),
  18. // and we spoil it with just one xrealloc here
  19. group_array = xrealloc(group_array, (n+1) * sizeof(group_array[0]));
  20. n = getgroups(n, group_array);
  21. /*
  22. * If buffer is too small, kernel does not return new_n > n.
  23. * It returns -1 and EINVAL:
  24. */
  25. if (n >= 0) {
  26. /* Terminator for bb_getgroups(NULL, NULL) usage */
  27. group_array[n] = (gid_t) -1;
  28. break;
  29. }
  30. if (errno == EINVAL) { /* too small? */
  31. /* This is the way to ask kernel how big the array is */
  32. n = getgroups(0, group_array);
  33. continue;
  34. }
  35. /* Some other error (should never happen on Linux) */
  36. bb_perror_msg_and_die("getgroups");
  37. }
  38. if (ngroups)
  39. *ngroups = n;
  40. return group_array;
  41. }