aboutsummaryrefslogtreecommitdiff
path: root/libpwdgrp
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2015-01-03 20:47:47 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2015-01-03 20:47:47 +0100
commit134c53098bdcbf7a0c34b60b97c46280d86eb48f (patch)
tree7c149d5eeb92085183e928908d8a648142fc4bb1 /libpwdgrp
parent20c0a16334e96493077eaaad6f4c5690af0aa6e8 (diff)
downloadbusybox-w32-134c53098bdcbf7a0c34b60b97c46280d86eb48f.tar.gz
busybox-w32-134c53098bdcbf7a0c34b60b97c46280d86eb48f.tar.bz2
busybox-w32-134c53098bdcbf7a0c34b60b97c46280d86eb48f.zip
libpwdgrp: store getXXnam result in a single malloc block
This saves a bit of memory but more importantly, allows to create xmalloc_getpwnam() API where result can be deleted simply using free(). function old new delta getXXnam 134 173 +39 parse_common 188 212 +24 convert_to_struct 277 290 +13 get_S 90 88 -2 tokenize 129 126 -3 bb_internal_getpwent_r 175 172 -3 getXXnam_r 208 198 -10 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/4 up/down: 76/-18) Total: 58 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'libpwdgrp')
-rw-r--r--libpwdgrp/pwd_grp.c58
1 files changed, 32 insertions, 26 deletions
diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c
index 1b2418a8d..4b61b61d2 100644
--- a/libpwdgrp/pwd_grp.c
+++ b/libpwdgrp/pwd_grp.c
@@ -34,24 +34,21 @@
34 34
35struct const_passdb { 35struct const_passdb {
36 const char *filename; 36 const char *filename;
37 const char def[9]; 37 const char def[7 + 2*ENABLE_USE_BB_SHADOW];
38 const uint8_t off[9]; 38 const uint8_t off[7 + 2*ENABLE_USE_BB_SHADOW];
39 uint8_t numfields; 39 uint8_t numfields;
40 uint8_t size_of;
40}; 41};
41struct passdb { 42struct passdb {
42 const char *filename; 43 const char *filename;
43 const char def[9]; 44 const char def[7 + 2*ENABLE_USE_BB_SHADOW];
44 const uint8_t off[9]; 45 const uint8_t off[7 + 2*ENABLE_USE_BB_SHADOW];
45 uint8_t numfields; 46 uint8_t numfields;
47 uint8_t size_of;
46 FILE *fp; 48 FILE *fp;
47 char *malloced; 49 char *malloced;
48 char struct_result[
49 /* Should be max(sizeof passwd,group,spwd), but this will do: */
50 IF_NOT_USE_BB_SHADOW(sizeof(struct passwd))
51 IF_USE_BB_SHADOW(sizeof(struct spwd))
52 ];
53}; 50};
54/* Note: for shadow db, def[9] will not contain terminating NUL, 51/* Note: for shadow db, def[] will not contain terminating NUL,
55 * but convert_to_struct() logic detects def[] end by "less than SP?", 52 * but convert_to_struct() logic detects def[] end by "less than SP?",
56 * not by "is it NUL?" condition; and off[0] happens to be zero 53 * not by "is it NUL?" condition; and off[0] happens to be zero
57 * for every db anyway, so there _is_ in fact a terminating NUL there. 54 * for every db anyway, so there _is_ in fact a terminating NUL there.
@@ -76,7 +73,7 @@ static const struct const_passdb const_pw_db = {
76 offsetof(struct passwd, pw_dir), /* 5 S */ 73 offsetof(struct passwd, pw_dir), /* 5 S */
77 offsetof(struct passwd, pw_shell) /* 6 S */ 74 offsetof(struct passwd, pw_shell) /* 6 S */
78 }, 75 },
79 sizeof(PW_DEF)-1 76 sizeof(PW_DEF)-1, sizeof(struct passwd)
80}; 77};
81static const struct const_passdb const_gr_db = { 78static const struct const_passdb const_gr_db = {
82 _PATH_GROUP, GR_DEF, 79 _PATH_GROUP, GR_DEF,
@@ -86,7 +83,7 @@ static const struct const_passdb const_gr_db = {
86 offsetof(struct group, gr_gid), /* 2 I */ 83 offsetof(struct group, gr_gid), /* 2 I */
87 offsetof(struct group, gr_mem) /* 3 m (char **) */ 84 offsetof(struct group, gr_mem) /* 3 m (char **) */
88 }, 85 },
89 sizeof(GR_DEF)-1 86 sizeof(GR_DEF)-1, sizeof(struct group)
90}; 87};
91#if ENABLE_USE_BB_SHADOW 88#if ENABLE_USE_BB_SHADOW
92static const struct const_passdb const_sp_db = { 89static const struct const_passdb const_sp_db = {
@@ -102,19 +99,20 @@ static const struct const_passdb const_sp_db = {
102 offsetof(struct spwd, sp_expire), /* 7 l */ 99 offsetof(struct spwd, sp_expire), /* 7 l */
103 offsetof(struct spwd, sp_flag) /* 8 r Reserved */ 100 offsetof(struct spwd, sp_flag) /* 8 r Reserved */
104 }, 101 },
105 sizeof(SP_DEF)-1 102 sizeof(SP_DEF)-1, sizeof(struct spwd)
106}; 103};
107#endif 104#endif
108 105
109/* We avoid having big global data. */ 106/* We avoid having big global data. */
110struct statics { 107struct statics {
111 /* It's ok to use same buffer (db[0].struct_result) for getpwuid and getpwnam. 108 /* It's ok to use same buffer (db[0].malloced) for getpwuid and getpwnam.
112 * Manpage says: 109 * Manpage says:
113 * "The return value may point to a static area, and may be overwritten 110 * "The return value may point to a static area, and may be overwritten
114 * by subsequent calls to getpwent(), getpwnam(), or getpwuid()." 111 * by subsequent calls to getpwent(), getpwnam(), or getpwuid()."
115 */ 112 */
116 struct passdb db[2 + ENABLE_USE_BB_SHADOW]; 113 struct passdb db[2 + ENABLE_USE_BB_SHADOW];
117 char *tokenize_end; 114 char *tokenize_end;
115 unsigned string_size;
118}; 116};
119 117
120static struct statics *ptr_to_statics; 118static struct statics *ptr_to_statics;
@@ -205,21 +203,21 @@ static char *parse_common(FILE *fp, const char *filename,
205 bb_error_msg("bad record at %s:%u", filename, count); 203 bb_error_msg("bad record at %s:%u", filename, count);
206 goto free_and_next; 204 goto free_and_next;
207 } 205 }
206 S.string_size = S.tokenize_end - buf;
208 207
209/* Ugly hack: group db requires aqdditional buffer space 208/* Ugly hack: group db requires additional buffer space
210 * for members[] array. If there is only one group, we need space 209 * for members[] array. If there is only one group, we need space
211 * for 3 pointers: alignment padding, group name, NULL. 210 * for 3 pointers: alignment padding, group name, NULL.
212 * +1 for every additional group. 211 * +1 for every additional group.
213 */ 212 */
214 if (n_fields == sizeof(GR_DEF)-1) { /* if we read group file */ 213 if (n_fields == sizeof(GR_DEF)-1) { /* if we read group file */
215 int resize = 3; 214 int cnt = 3;
216 char *p = buf; 215 char *p = buf;
217 while (*p) 216 while (*p)
218 if (*p++ == ',') 217 if (*p++ == ',')
219 resize++; 218 cnt++;
220 resize *= sizeof(char**); 219 S.string_size += cnt * sizeof(char*);
221 resize += S.tokenize_end - buf; 220 buf = xrealloc(buf, S.string_size);
222 buf = xrealloc(buf, resize);
223 } 221 }
224 222
225 if (!key) { 223 if (!key) {
@@ -258,8 +256,8 @@ static void *convert_to_struct(struct passdb *db,
258 const char *def = db->def; 256 const char *def = db->def;
259 const uint8_t *off = db->off; 257 const uint8_t *off = db->off;
260 258
261/* TODO? for consistency, zero out all fields */ 259 /* For consistency, zero out all fields */
262/* memset(result, 0, size_of_result);*/ 260 memset(result, 0, db->size_of);
263 261
264 for (;;) { 262 for (;;) {
265 void *member = (char*)result + (*off++); 263 void *member = (char*)result + (*off++);
@@ -305,7 +303,7 @@ static void *convert_to_struct(struct passdb *db,
305 /* def "r" does nothing */ 303 /* def "r" does nothing */
306 304
307 def++; 305 def++;
308 if ((unsigned char)*def < (unsigned char)' ') 306 if ((unsigned char)*def <= (unsigned char)' ')
309 break; 307 break;
310 buffer += strlen(buffer) + 1; 308 buffer += strlen(buffer) + 1;
311 } 309 }
@@ -328,7 +326,9 @@ static int FAST_FUNC getXXnam_r(const char *name, uintptr_t db_and_field_pos,
328 db = &S.db[db_and_field_pos >> 2]; 326 db = &S.db[db_and_field_pos >> 2];
329 327
330 *(void**)result = NULL; 328 *(void**)result = NULL;
331 buf = parse_file(db->filename, db->numfields, name, db_and_field_pos & 3); 329 buf = parse_file(db->filename, db->numfields, name, 0 /*db_and_field_pos & 3*/);
330 /* "db_and_field_pos & 3" is commented out since so far we don't implement
331 * getXXXid_r() functions which would use that to pass 2 here */
332 if (buf) { 332 if (buf) {
333 size_t size = S.tokenize_end - buf; 333 size_t size = S.tokenize_end - buf;
334 if (size > buflen) { 334 if (size > buflen) {
@@ -433,8 +433,14 @@ static void* FAST_FUNC getXXnam(const char *name, unsigned db_and_field_pos)
433 buf = parse_common(db->fp, db->filename, db->numfields, name, db_and_field_pos & 3); 433 buf = parse_common(db->fp, db->filename, db->numfields, name, db_and_field_pos & 3);
434 if (buf) { 434 if (buf) {
435 free(db->malloced); 435 free(db->malloced);
436 db->malloced = buf; 436 /* We enlarge buf and move string data up, freeing space
437 result = convert_to_struct(db, buf, db->struct_result); 437 * for struct passwd/group/spwd at the beginning. This way,
438 * entire result of getXXnam is in a single malloced block.
439 * This enables easy creation of xmalloc_getpwnam() API.
440 */
441 db->malloced = buf = xrealloc(buf, db->size_of + S.string_size);
442 memmove(buf + db->size_of, buf, S.string_size);
443 result = convert_to_struct(db, buf + db->size_of, buf);
438 } 444 }
439 return result; 445 return result;
440} 446}