summaryrefslogtreecommitdiff
path: root/libshouldbeinlibc/idvec-rep.c
blob: 2fa1be0335064cfb0ac00b7734ed006574104dcb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/* idvec string representation

   Copyright (C) 1996, 1997 Free Software Foundation, Inc.

   Written by Miles Bader <miles@gnu.ai.mit.edu>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2, or (at
   your option) any later version.

   This program 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
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <idvec.h>
#include <grp.h>
#include <pwd.h>

/* Return a string representation of the ids in IDVEC, each id separated by
   the string SEP (default ",").  SHOW_VALUES and SHOW_NAMES reflect how each
   id is printed (if SHOW_NAMES is true values are used where names aren't
   available); if both are true, the `VALUE(NAME)' format is used.
   ID_NAME_FN is used to map each id to a name; it should return a malloced
   string, which will be freed here.  The empty string is returned for an
   empty list, and 0 for an allocation error.  */
char *
idvec_rep (const struct idvec *idvec, int show_values, int show_names,
	   char *(*id_name_fn) (uid_t id), const char *sep)
{
  size_t sep_len;
  char *rep = 0;
  size_t rep_len = 0, rep_sz = 0;

  int ensure_room (size_t amount)
    {
      size_t end = rep_len + amount;
      if (end > rep_sz)
	{
	  size_t new_sz = rep_sz + end;
	  char *new_rep = realloc (rep, new_sz);
	  if (new_rep)
	    {
	      rep = new_rep;
	      rep_sz = new_sz;
	    }
	  else
	    return 0;
	}
      return 1;
    }
  int add_id (uid_t val, char *name)
    {
      if (!name || show_values)
	{
	  if (! ensure_room (10))
	    return 0;
	  rep_len += snprintf (rep + rep_len, 10, "%d", val);
	}
      if (name)
	{
	  size_t nlen = strlen (name) + 3;
	  if (! ensure_room (nlen))
	    {
	      free (name);
	      return 0;
	    }
	  rep_len +=
	    snprintf (rep + rep_len, nlen, show_values ? "(%s)" : "%s", name);
	  free (name);
	}
      return 1;
    }

  if (! sep)
    sep = ",";
  sep_len = strlen (sep);

  if (idvec->num > 0)
    {
      int i;

      for (i = 0; i < idvec->num; i++)
	{
	  char *name = 0;
	  uid_t val = idvec->ids[i];

	  if (i > 0)
	    if (ensure_room (sep_len))
	      {
		strcpy (rep + rep_len, sep);
		rep_len += sep_len;
	      }
	    else
	      break;

	  if (show_names || !show_values)
	    name = (*id_name_fn) (val);
	  if (! add_id (val, name))
	    break;
	}

      if (i < idvec->num)
	{
	  free (rep);
	  return 0;
	}

      return rep;
    }

  return strdup ("");
}

/* Return a malloced string with the name of the user UID.  */
static char *
lookup_uid (uid_t uid)
{
  char buf[1024];
  struct passwd _pw, *pw;
  if (getpwuid_r (uid, &_pw, buf, sizeof buf, &pw) == 0)
    return strdup (pw->pw_name);
  else
    return 0;
}

/* Return a malloced string with the name of the group GID.  */
static char *
lookup_gid (gid_t gid)
{
  char buf[1024];
  struct group _gr, *gr;
  if (getgrgid_r (gid, &_gr, buf, sizeof buf, &gr) == 0)
    return strdup (gr->gr_name);
  else
    return 0;
}

/* Like idvec_rep, mapping ids to user names.  */
char *
idvec_uids_rep (const struct idvec *idvec, int show_values, int show_names,
		const char *sep)
{
  return idvec_rep (idvec, show_values, show_names, lookup_uid, sep);
}

/* Like idvec_rep, mapping ids to group names.  */
char *
idvec_gids_rep (const struct idvec *idvec, int show_values, int show_names,
		const char *sep)
{
  return idvec_rep (idvec, show_values, show_names, lookup_gid, sep);
}