busybox/libbb/bb_getgroups.c
<<
>>
Prefs
   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
   9//kbuild:lib-y += bb_getgroups.o
  10
  11#include "libbb.h"
  12
  13gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array)
  14{
  15        int n = ngroups ? *ngroups : 0;
  16
  17        /* getgroups may be a bit expensive, try to use it only once */
  18        if (n < 32)
  19                n = 32;
  20
  21        for (;;) {
  22// FIXME: ash tries so hard to not die on OOM (when we are called from test),
  23// and we spoil it with just one xrealloc here
  24                group_array = xrealloc(group_array, (n+1) * sizeof(group_array[0]));
  25                n = getgroups(n, group_array);
  26                /*
  27                 * If buffer is too small, kernel does not return new_n > n.
  28                 * It returns -1 and EINVAL:
  29                 */
  30                if (n >= 0) {
  31                        /* Terminator for bb_getgroups(NULL, NULL) usage */
  32                        group_array[n] = (gid_t) -1;
  33                        break;
  34                }
  35                if (errno == EINVAL) { /* too small? */
  36                        /* This is the way to ask kernel how big the array is */
  37                        n = getgroups(0, group_array);
  38                        continue;
  39                }
  40                /* Some other error (should never happen on Linux) */
  41                bb_perror_msg_and_die("getgroups");
  42        }
  43
  44        if (ngroups)
  45                *ngroups = n;
  46        return group_array;
  47}
  48