OSDN Git Service

mkostemp: fix implementation
[uclinux-h8/uClibc.git] / libc / pwd_grp / pwd_grp.c
1 /*
2  * Copyright (C) 2003     Manuel Novoa III <mjn3@uclibc.org>
3  * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4  *
5  * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
6  */
7
8 /*  Nov 6, 2003  Initial version.
9  *
10  *  NOTE: This implementation is quite strict about requiring all
11  *    field seperators.  It also does not allow leading whitespace
12  *    except when processing the numeric fields.  glibc is more
13  *    lenient.  See the various glibc difference comments below.
14  *
15  *  TODO:
16  *    Move to dynamic allocation of (currently statically allocated)
17  *      buffers; especially for the group-related functions since
18  *      large group member lists will cause error returns.
19  *
20  */
21
22 #include <features.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdint.h>
26 #include <string.h>
27 #include <stddef.h>
28 #include <errno.h>
29 #include <assert.h>
30 #include <ctype.h>
31 #include <pwd.h>
32 #include <grp.h>
33 #include <paths.h>
34 #ifdef __UCLIBC_HAS_SHADOW__
35 # include <shadow.h>
36 #endif
37 #include <bits/uClibc_mutex.h>
38
39 /**********************************************************************/
40 /* Prototypes for internal functions. */
41
42 extern int __parsepwent(void *pw, char *line) attribute_hidden;
43 extern int __parsegrent(void *gr, char *line) attribute_hidden;
44 extern int __parsespent(void *sp, char *line) attribute_hidden;
45
46 extern int __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
47                            char *__restrict line_buff, size_t buflen, FILE *f) attribute_hidden;
48
49 extern gid_t* __getgrouplist_internal(const char *user, gid_t gid, int *ngroups) attribute_hidden;
50
51 /**********************************************************************/
52 /* For the various fget??ent_r funcs, return
53  *
54  *  0: success
55  *  ENOENT: end-of-file encountered
56  *  ERANGE: buflen too small
57  *  other error values possible. See __pgsreader.
58  *
59  * Also, *result == resultbuf on success and NULL on failure.
60  *
61  * NOTE: glibc difference - For the ENOENT case, glibc also sets errno.
62  *   We do not, as it really isn't an error if we reach the end-of-file.
63  *   Doing so is analogous to having fgetc() set errno on EOF.
64  */
65 /**********************************************************************/
66 #ifdef L_fgetpwent_r
67
68 #ifdef __USE_SVID
69 int fgetpwent_r(FILE *__restrict stream, struct passwd *__restrict resultbuf,
70                                 char *__restrict buffer, size_t buflen,
71                                 struct passwd **__restrict result)
72 {
73         int rv;
74
75         *result = NULL;
76
77         if (!(rv = __pgsreader(__parsepwent, resultbuf, buffer, buflen, stream))) {
78                 *result = resultbuf;
79         }
80
81         return rv;
82 }
83 libc_hidden_def(fgetpwent_r)
84 #endif
85
86 #endif
87 /**********************************************************************/
88 #ifdef L_fgetgrent_r
89
90 #ifdef __USE_SVID
91 int fgetgrent_r(FILE *__restrict stream, struct group *__restrict resultbuf,
92                                 char *__restrict buffer, size_t buflen,
93                                 struct group **__restrict result)
94 {
95         int rv;
96
97         *result = NULL;
98
99         if (!(rv = __pgsreader(__parsegrent, resultbuf, buffer, buflen, stream))) {
100                 *result = resultbuf;
101         }
102
103         return rv;
104 }
105 libc_hidden_def(fgetgrent_r)
106 #endif
107
108 #endif
109 /**********************************************************************/
110 #ifdef L_fgetspent_r
111
112 int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf,
113                                 char *__restrict buffer, size_t buflen,
114                                 struct spwd **__restrict result)
115 {
116         int rv;
117
118         *result = NULL;
119
120         if (!(rv = __pgsreader(__parsespent, resultbuf, buffer, buflen, stream))) {
121                 *result = resultbuf;
122         }
123
124         return rv;
125 }
126 libc_hidden_def(fgetspent_r)
127
128 #endif
129 /**********************************************************************/
130 /* For the various fget??ent funcs, return NULL on failure and a
131  * pointer to the appropriate struct (statically allocated) on success.
132  */
133 /**********************************************************************/
134 #ifdef L_fgetpwent
135
136 #ifdef __USE_SVID
137
138 struct passwd *fgetpwent(FILE *stream)
139 {
140         static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
141         static struct passwd resultbuf;
142         struct passwd *result;
143
144         fgetpwent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
145         return result;
146 }
147 #endif
148
149 #endif
150 /**********************************************************************/
151 #ifdef L_fgetgrent
152
153 #ifdef __USE_SVID
154
155 struct group *fgetgrent(FILE *stream)
156 {
157         static char buffer[__UCLIBC_GRP_BUFFER_SIZE__];
158         static struct group resultbuf;
159         struct group *result;
160
161         fgetgrent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
162         return result;
163 }
164 #endif
165
166 #endif
167 /**********************************************************************/
168 #ifdef L_fgetspent
169
170
171 struct spwd *fgetspent(FILE *stream)
172 {
173         static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
174         static struct spwd resultbuf;
175         struct spwd *result;
176
177         fgetspent_r(stream, &resultbuf, buffer, sizeof(buffer), &result);
178         return result;
179 }
180
181 #endif
182 /**********************************************************************/
183 #ifdef L_sgetspent_r
184
185 int sgetspent_r(const char *string, struct spwd *result_buf,
186                                 char *buffer, size_t buflen, struct spwd **result)
187 {
188         int rv = ERANGE;
189
190         *result = NULL;
191
192         if (buflen < __UCLIBC_PWD_BUFFER_SIZE__) {
193         DO_ERANGE:
194                 __set_errno(rv);
195                 goto DONE;
196         }
197
198         if (string != buffer) {
199                 if (strlen(string) >= buflen) {
200                         goto DO_ERANGE;
201                 }
202                 strcpy(buffer, string);
203         }
204
205         if (!(rv = __parsespent(result_buf, buffer))) {
206                 *result = result_buf;
207         }
208
209  DONE:
210         return rv;
211 }
212 libc_hidden_def(sgetspent_r)
213
214 #endif
215 /**********************************************************************/
216
217 #ifdef GETXXKEY_R_FUNC
218 #error GETXXKEY_R_FUNC is already defined!
219 #endif
220
221 #ifdef L_getpwnam_r
222 #define GETXXKEY_R_FUNC         getpwnam_r
223 #define GETXXKEY_R_PARSER       __parsepwent
224 #define GETXXKEY_R_ENTTYPE      struct passwd
225 #define GETXXKEY_R_TEST(ENT)    (!strcmp((ENT)->pw_name, key))
226 #define DO_GETXXKEY_R_KEYTYPE   const char *__restrict
227 #define DO_GETXXKEY_R_PATHNAME  _PATH_PASSWD
228 #include "pwd_grp_internal.c"
229 #endif
230
231 #ifdef L_getgrnam_r
232 #define GETXXKEY_R_FUNC         getgrnam_r
233 #define GETXXKEY_R_PARSER       __parsegrent
234 #define GETXXKEY_R_ENTTYPE      struct group
235 #define GETXXKEY_R_TEST(ENT)    (!strcmp((ENT)->gr_name, key))
236 #define DO_GETXXKEY_R_KEYTYPE   const char *__restrict
237 #define DO_GETXXKEY_R_PATHNAME  _PATH_GROUP
238 #include "pwd_grp_internal.c"
239 #endif
240
241 #ifdef L_getspnam_r
242 #define GETXXKEY_R_FUNC         getspnam_r
243 #define GETXXKEY_R_PARSER       __parsespent
244 #define GETXXKEY_R_ENTTYPE      struct spwd
245 #define GETXXKEY_R_TEST(ENT)    (!strcmp((ENT)->sp_namp, key))
246 #define DO_GETXXKEY_R_KEYTYPE   const char *__restrict
247 #define DO_GETXXKEY_R_PATHNAME  _PATH_SHADOW
248 #include "pwd_grp_internal.c"
249 #endif
250
251 #ifdef L_getpwuid_r
252 #define GETXXKEY_R_FUNC         getpwuid_r
253 #define GETXXKEY_R_PARSER       __parsepwent
254 #define GETXXKEY_R_ENTTYPE      struct passwd
255 #define GETXXKEY_R_TEST(ENT)    ((ENT)->pw_uid == key)
256 #define DO_GETXXKEY_R_KEYTYPE   uid_t
257 #define DO_GETXXKEY_R_PATHNAME  _PATH_PASSWD
258 #include "pwd_grp_internal.c"
259 #endif
260
261 #ifdef L_getgrgid_r
262 #define GETXXKEY_R_FUNC         getgrgid_r
263 #define GETXXKEY_R_PARSER       __parsegrent
264 #define GETXXKEY_R_ENTTYPE      struct group
265 #define GETXXKEY_R_TEST(ENT)    ((ENT)->gr_gid == key)
266 #define DO_GETXXKEY_R_KEYTYPE   gid_t
267 #define DO_GETXXKEY_R_PATHNAME  _PATH_GROUP
268 #include "pwd_grp_internal.c"
269 #endif
270
271 /**********************************************************************/
272 #ifdef L_getpwuid
273
274
275 struct passwd *getpwuid(uid_t uid)
276 {
277         static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
278         static struct passwd resultbuf;
279         struct passwd *result;
280
281         getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
282         return result;
283 }
284
285 #endif
286 /**********************************************************************/
287 #ifdef L_getgrgid
288
289
290 struct group *getgrgid(gid_t gid)
291 {
292         static char buffer[__UCLIBC_GRP_BUFFER_SIZE__];
293         static struct group resultbuf;
294         struct group *result;
295
296         getgrgid_r(gid, &resultbuf, buffer, sizeof(buffer), &result);
297         return result;
298 }
299
300 #endif
301 /**********************************************************************/
302 #ifdef L_getspuid_r
303
304 /* This function is non-standard and is currently not built.  It seems
305  * to have been created as a reentrant version of the non-standard
306  * functions getspuid.  Why getspuid was added, I do not know. */
307
308
309 int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf,
310                        char *__restrict buffer, size_t buflen,
311                        struct spwd **__restrict result)
312 {
313         int rv;
314         struct passwd *pp;
315         struct passwd password;
316         char pwd_buff[__UCLIBC_PWD_BUFFER_SIZE__];
317
318         *result = NULL;
319         if (!(rv = getpwuid_r(uid, &password, pwd_buff, sizeof(pwd_buff), &pp))) {
320                 rv = getspnam_r(password.pw_name, resultbuf, buffer, buflen, result);
321         }
322
323         return rv;
324 }
325
326 #endif
327 /**********************************************************************/
328 #ifdef L_getspuid
329
330 /* This function is non-standard and is currently not built.
331  * Why it was added, I do not know. */
332
333 struct spwd *getspuid(uid_t uid)
334 {
335         static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
336         static struct spwd resultbuf;
337         struct spwd *result;
338
339         getspuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result);
340         return result;
341 }
342
343 #endif
344 /**********************************************************************/
345 #ifdef L_getpwnam
346
347
348 struct passwd *getpwnam(const char *name)
349 {
350         static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
351         static struct passwd resultbuf;
352         struct passwd *result;
353
354         getpwnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
355         return result;
356 }
357 libc_hidden_def(getpwnam)
358
359 #endif
360 /**********************************************************************/
361 #ifdef L_getgrnam
362
363
364 struct group *getgrnam(const char *name)
365 {
366         static char buffer[__UCLIBC_GRP_BUFFER_SIZE__];
367         static struct group resultbuf;
368         struct group *result;
369
370         getgrnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
371         return result;
372 }
373
374 #endif
375 /**********************************************************************/
376 #ifdef L_getspnam
377
378
379 struct spwd *getspnam(const char *name)
380 {
381         static char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
382         static struct spwd resultbuf;
383         struct spwd *result;
384
385         getspnam_r(name, &resultbuf, buffer, sizeof(buffer), &result);
386         return result;
387 }
388
389 #endif
390 /**********************************************************************/
391 #ifdef L_getpw
392
393
394 int getpw(uid_t uid, char *buf)
395 {
396         struct passwd resultbuf;
397         struct passwd *result;
398         char buffer[__UCLIBC_PWD_BUFFER_SIZE__];
399
400         if (!buf) {
401                 __set_errno(EINVAL);
402         } else if (!getpwuid_r(uid, &resultbuf, buffer, sizeof(buffer), &result)) {
403                 if (sprintf(buf, "%s:%s:%lu:%lu:%s:%s:%s\n",
404                                         resultbuf.pw_name, resultbuf.pw_passwd,
405                                         (unsigned long)(resultbuf.pw_uid),
406                                         (unsigned long)(resultbuf.pw_gid),
407                                         resultbuf.pw_gecos, resultbuf.pw_dir,
408                                         resultbuf.pw_shell) >= 0
409                         ) {
410                         return 0;
411                 }
412         }
413
414         return -1;
415 }
416
417 #endif
418 /**********************************************************************/
419
420 #ifdef L_getpwent_r
421 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
422
423 static FILE *pwf /*= NULL*/;
424
425 void setpwent(void)
426 {
427         __UCLIBC_MUTEX_LOCK(mylock);
428         if (pwf) {
429                 rewind(pwf);
430         }
431         __UCLIBC_MUTEX_UNLOCK(mylock);
432 }
433
434 void endpwent(void)
435 {
436         __UCLIBC_MUTEX_LOCK(mylock);
437         if (pwf) {
438                 fclose(pwf);
439                 pwf = NULL;
440         }
441         __UCLIBC_MUTEX_UNLOCK(mylock);
442 }
443
444
445 int getpwent_r(struct passwd *__restrict resultbuf,
446                            char *__restrict buffer, size_t buflen,
447                            struct passwd **__restrict result)
448 {
449         int rv;
450
451         __UCLIBC_MUTEX_LOCK(mylock);
452
453         *result = NULL;                         /* In case of error... */
454
455         if (!pwf) {
456                 if (!(pwf = fopen(_PATH_PASSWD, "r"))) {
457                         rv = errno;
458                         goto ERR;
459                 }
460                 __STDIO_SET_USER_LOCKING(pwf);
461         }
462
463         if (!(rv = __pgsreader(__parsepwent, resultbuf,
464                                                    buffer, buflen, pwf))) {
465                 *result = resultbuf;
466         }
467
468  ERR:
469         __UCLIBC_MUTEX_UNLOCK(mylock);
470
471         return rv;
472 }
473 libc_hidden_def(getpwent_r)
474
475 #endif
476 /**********************************************************************/
477 #ifdef L_getgrent_r
478 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
479
480 static FILE *grf /*= NULL*/;
481
482 void setgrent(void)
483 {
484         __UCLIBC_MUTEX_LOCK(mylock);
485         if (grf) {
486                 rewind(grf);
487         }
488         __UCLIBC_MUTEX_UNLOCK(mylock);
489 }
490
491 void endgrent(void)
492 {
493         __UCLIBC_MUTEX_LOCK(mylock);
494         if (grf) {
495                 fclose(grf);
496                 grf = NULL;
497         }
498         __UCLIBC_MUTEX_UNLOCK(mylock);
499 }
500
501 int getgrent_r(struct group *__restrict resultbuf,
502                            char *__restrict buffer, size_t buflen,
503                            struct group **__restrict result)
504 {
505         int rv;
506
507         __UCLIBC_MUTEX_LOCK(mylock);
508
509         *result = NULL;                         /* In case of error... */
510
511         if (!grf) {
512                 if (!(grf = fopen(_PATH_GROUP, "r"))) {
513                         rv = errno;
514                         goto ERR;
515                 }
516                 __STDIO_SET_USER_LOCKING(grf);
517         }
518
519         if (!(rv = __pgsreader(__parsegrent, resultbuf,
520                                                    buffer, buflen, grf))) {
521                 *result = resultbuf;
522         }
523
524  ERR:
525         __UCLIBC_MUTEX_UNLOCK(mylock);
526
527         return rv;
528 }
529 libc_hidden_def(getgrent_r)
530
531 #endif
532 /**********************************************************************/
533 #ifdef L_getspent_r
534 __UCLIBC_MUTEX_STATIC(mylock, PTHREAD_MUTEX_INITIALIZER);
535
536 static FILE *spf /*= NULL*/;
537
538 void setspent(void)
539 {
540         __UCLIBC_MUTEX_LOCK(mylock);
541         if (spf) {
542                 rewind(spf);
543         }
544         __UCLIBC_MUTEX_UNLOCK(mylock);
545 }
546
547 void endspent(void)
548 {
549         __UCLIBC_MUTEX_LOCK(mylock);
550         if (spf) {
551                 fclose(spf);
552                 spf = NULL;
553         }
554         __UCLIBC_MUTEX_UNLOCK(mylock);
555 }
556
557 int getspent_r(struct spwd *resultbuf, char *buffer,
558                            size_t buflen, struct spwd **result)
559 {
560         int rv;
561
562         __UCLIBC_MUTEX_LOCK(mylock);
563
564         *result = NULL;                         /* In case of error... */
565
566         if (!spf) {
567                 if (!(spf = fopen(_PATH_SHADOW, "r"))) {
568                         rv = errno;
569                         goto ERR;
570                 }
571                 __STDIO_SET_USER_LOCKING(spf);
572         }
573
574         if (!(rv = __pgsreader(__parsespent, resultbuf,
575                                                    buffer, buflen, spf))) {
576                 *result = resultbuf;
577         }
578
579  ERR:
580         __UCLIBC_MUTEX_UNLOCK(mylock);
581
582         return rv;
583 }
584 libc_hidden_def(getspent_r)
585
586 #endif
587 /**********************************************************************/
588 #ifdef L_getpwent
589
590
591 struct passwd *getpwent(void)
592 {
593         static char line_buff[__UCLIBC_PWD_BUFFER_SIZE__];
594         static struct passwd pwd;
595         struct passwd *result;
596
597         getpwent_r(&pwd, line_buff, sizeof(line_buff), &result);
598         return result;
599 }
600
601 #endif
602 /**********************************************************************/
603 #ifdef L_getgrent
604
605
606 struct group *getgrent(void)
607 {
608         static char line_buff[__UCLIBC_GRP_BUFFER_SIZE__];
609         static struct group gr;
610         struct group *result;
611
612         getgrent_r(&gr, line_buff, sizeof(line_buff), &result);
613         return result;
614 }
615
616 #endif
617 /**********************************************************************/
618 #ifdef L_getspent
619
620
621 struct spwd *getspent(void)
622 {
623         static char line_buff[__UCLIBC_PWD_BUFFER_SIZE__];
624         static struct spwd spwd;
625         struct spwd *result;
626
627         getspent_r(&spwd, line_buff, sizeof(line_buff), &result);
628         return result;
629 }
630
631 #endif
632 /**********************************************************************/
633 #ifdef L_sgetspent
634
635
636 struct spwd *sgetspent(const char *string)
637 {
638         static char line_buff[__UCLIBC_PWD_BUFFER_SIZE__];
639         static struct spwd spwd;
640         struct spwd *result;
641
642         sgetspent_r(string, &spwd, line_buff, sizeof(line_buff), &result);
643         return result;
644 }
645
646 #endif
647 /**********************************************************************/
648 #ifdef L___getgrouplist_internal
649
650 gid_t attribute_hidden *__getgrouplist_internal(const char *user, gid_t gid, int *ngroups)
651 {
652         FILE *grfile;
653         gid_t *group_list;
654         int num_groups;
655         struct group group;
656         char buff[__UCLIBC_PWD_BUFFER_SIZE__];
657
658         *ngroups = num_groups = 1;
659
660         /* We alloc space for 8 gids at a time. */
661         group_list = malloc(8 * sizeof(group_list[0]));
662         if (!group_list)
663                 return NULL;
664
665         group_list[0] = gid;
666         grfile = fopen(_PATH_GROUP, "r");
667         /* If /etc/group doesn't exist, we still return 1-element vector */
668         if (!grfile)
669                 return group_list;
670
671         __STDIO_SET_USER_LOCKING(grfile);
672
673         while (!__pgsreader(__parsegrent, &group, buff, sizeof(buff), grfile)) {
674                 char **m;
675
676                 assert(group.gr_mem); /* Must have at least a NULL terminator. */
677                 if (group.gr_gid == gid)
678                         continue;
679                 for (m = group.gr_mem; *m; m++) {
680                         if (strcmp(*m, user) != 0)
681                                 continue;
682                         if (!(num_groups & 7)) {
683                                 gid_t *tmp = realloc(group_list, (num_groups+8) * sizeof(group_list[0]));
684                                 if (!tmp)
685                                         goto DO_CLOSE;
686                                 group_list = tmp;
687                         }
688                         group_list[num_groups++] = group.gr_gid;
689                         break;
690                 }
691         }
692
693  DO_CLOSE:
694         fclose(grfile);
695         *ngroups = num_groups;
696         return group_list;
697 }
698
699 #endif
700 /**********************************************************************/
701 #ifdef L_getgrouplist
702
703 #if defined __USE_BSD || defined __USE_GNU
704 int getgrouplist(const char *user, gid_t gid, gid_t *groups, int *ngroups)
705 {
706         int sz = *ngroups;
707         gid_t *group_list = __getgrouplist_internal(user, gid, ngroups);
708
709         if (!group_list) {
710                 /* malloc failure - what shall we do?
711                  * fail with ENOMEM? I bet users never check for that */
712                 /* *ngroups = 1; - already done by __getgrouplist_internal */
713                 if (sz) {
714                         groups[0] = gid;
715                         return 1;
716                 }
717                 return -1;
718         }
719         /* *ngroups is non-zero here */
720
721         if (sz > *ngroups)
722                 sz = *ngroups;
723         if (sz)
724                 memcpy(groups, group_list, sz * sizeof(group_list[0]));
725         free(group_list);
726         if (sz < *ngroups)
727                 return -1;
728         return sz;
729 }
730 #endif
731
732 #endif
733 /**********************************************************************/
734 #ifdef L_initgroups
735
736 #ifdef __USE_BSD
737
738 int initgroups(const char *user, gid_t gid)
739 {
740         int rv;
741         int num_groups = ((unsigned)~0) >> 1; /* INT_MAX */
742         gid_t *group_list = __getgrouplist_internal(user, gid, &num_groups);
743         if (!group_list)
744                 return -1;
745         rv = setgroups(num_groups, group_list);
746         free(group_list);
747         return rv;
748 }
749 #endif
750
751 #endif
752 /**********************************************************************/
753 #ifdef L_putpwent
754
755 #ifdef __USE_SVID
756 int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
757 {
758         int rv = -1;
759
760         if (!p || !f) {
761                 __set_errno(EINVAL);
762         } else {
763                 /* No extra thread locking is needed above what fprintf does. */
764                 if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
765                                         p->pw_name, p->pw_passwd,
766                                         (unsigned long)(p->pw_uid),
767                                         (unsigned long)(p->pw_gid),
768                                         p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
769                         ) {
770                         rv = 0;
771                 }
772         }
773
774         return rv;
775 }
776 #endif
777
778 #endif
779 /**********************************************************************/
780 #ifdef L_putgrent
781
782 int putgrent(const struct group *__restrict p, FILE *__restrict f)
783 {
784         static const char format[] = ",%s";
785         char **m;
786         const char *fmt;
787         int rv = -1;
788         __STDIO_AUTO_THREADLOCK_VAR;
789
790         if (!p || !f) {                         /* Sigh... glibc checks. */
791                 __set_errno(EINVAL);
792         } else {
793                 __STDIO_AUTO_THREADLOCK(f);
794
795                 if (fprintf(f, "%s:%s:%lu:",
796                                         p->gr_name, p->gr_passwd,
797                                         (unsigned long)(p->gr_gid)) >= 0
798                         ) {
799
800                         fmt = format + 1;
801
802                         assert(p->gr_mem);
803                         m = p->gr_mem;
804
805                         do {
806                                 if (!*m) {
807                                         if (__fputc_unlocked('\n', f) >= 0) {
808                                                 rv = 0;
809                                         }
810                                         break;
811                                 }
812                                 if (fprintf(f, fmt, *m) < 0) {
813                                         break;
814                                 }
815                                 ++m;
816                                 fmt = format;
817                         } while (1);
818
819                 }
820
821                 __STDIO_AUTO_THREADUNLOCK(f);
822         }
823
824         return rv;
825 }
826
827 #endif
828 /**********************************************************************/
829 #ifdef L_putspent
830
831 static const unsigned char _sp_off[] = {
832         offsetof(struct spwd, sp_lstchg),       /* 2 - not a char ptr */
833         offsetof(struct spwd, sp_min),          /* 3 - not a char ptr */
834         offsetof(struct spwd, sp_max),          /* 4 - not a char ptr */
835         offsetof(struct spwd, sp_warn),         /* 5 - not a char ptr */
836         offsetof(struct spwd, sp_inact),        /* 6 - not a char ptr */
837         offsetof(struct spwd, sp_expire),       /* 7 - not a char ptr */
838 };
839
840 int putspent(const struct spwd *p, FILE *stream)
841 {
842         static const char ld_format[] = "%ld:";
843         const char *f;
844         long int x;
845         size_t i;
846         int rv = -1;
847         __STDIO_AUTO_THREADLOCK_VAR;
848
849         /* Unlike putpwent and putgrent, glibc does not check the args. */
850
851         __STDIO_AUTO_THREADLOCK(stream);
852
853         if (fprintf(stream, "%s:%s:", p->sp_namp,
854                                 (p->sp_pwdp ? p->sp_pwdp : "")) < 0
855                 ) {
856                 goto DO_UNLOCK;
857         }
858
859         for (i=0 ; i < sizeof(_sp_off) ; i++) {
860                 f = ld_format;
861                 if ((x = *(const long int *)(((const char *) p) + _sp_off[i])) == -1) {
862                         f += 3;
863                 }
864                 if (fprintf(stream, f, x) < 0) {
865                         goto DO_UNLOCK;
866                 }
867         }
868
869         if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
870                 goto DO_UNLOCK;
871         }
872
873         if (__fputc_unlocked('\n', stream) > 0) {
874                 rv = 0;
875         }
876
877  DO_UNLOCK:
878         __STDIO_AUTO_THREADUNLOCK(stream);
879
880         return rv;
881 }
882
883 #endif
884 /**********************************************************************/
885 /* Internal uClibc functions.                                         */
886 /**********************************************************************/
887 #ifdef L___parsepwent
888
889 static const unsigned char pw_off[] = {
890         offsetof(struct passwd, pw_name),       /* 0 */
891         offsetof(struct passwd, pw_passwd),     /* 1 */
892         offsetof(struct passwd, pw_uid),        /* 2 - not a char ptr */
893         offsetof(struct passwd, pw_gid),        /* 3 - not a char ptr */
894         offsetof(struct passwd, pw_gecos),      /* 4 */
895         offsetof(struct passwd, pw_dir),        /* 5 */
896         offsetof(struct passwd, pw_shell)       /* 6 */
897 };
898
899 int attribute_hidden __parsepwent(void *data, char *line)
900 {
901         char *endptr;
902         char *p;
903         int i;
904
905         i = 0;
906         do {
907                 p = ((char *) ((struct passwd *) data)) + pw_off[i];
908
909                 if ((i & 6) ^ 2) {      /* i!=2 and i!=3 */
910                         *((char **) p) = line;
911                         if (i==6) {
912                                 return 0;
913                         }
914                         /* NOTE: glibc difference - glibc allows omission of
915                          * ':' seperators after the gid field if all remaining
916                          * entries are empty.  We require all separators. */
917                         if (!(line = strchr(line, ':'))) {
918                                 break;
919                         }
920                 } else {
921                         unsigned long t = strtoul(line, &endptr, 10);
922                         /* Make sure we had at least one digit, and that the
923                          * failing char is the next field seperator ':'.  See
924                          * glibc difference note above. */
925                         /* TODO: Also check for leading whitespace? */
926                         if ((endptr == line) || (*endptr != ':')) {
927                                 break;
928                         }
929                         line = endptr;
930                         if (i & 1) {            /* i == 3 -- gid */
931                                 *((gid_t *) p) = t;
932                         } else {                        /* i == 2 -- uid */
933                                 *((uid_t *) p) = t;
934                         }
935                 }
936
937                 *line++ = 0;
938                 ++i;
939         } while (1);
940
941         return -1;
942 }
943
944 #endif
945 /**********************************************************************/
946 #ifdef L___parsegrent
947
948 static const unsigned char gr_off[] = {
949         offsetof(struct group, gr_name),        /* 0 */
950         offsetof(struct group, gr_passwd),      /* 1 */
951         offsetof(struct group, gr_gid)          /* 2 - not a char ptr */
952 };
953
954 int attribute_hidden __parsegrent(void *data, char *line)
955 {
956         char *endptr;
957         char *p;
958         int i;
959         char **members;
960         char *end_of_buf;
961
962         end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
963         i = 0;
964         do {
965                 p = ((char *) ((struct group *) data)) + gr_off[i];
966
967                 if (i < 2) {
968                         *((char **) p) = line;
969                         if (!(line = strchr(line, ':'))) {
970                                 break;
971                         }
972                         *line++ = 0;
973                         ++i;
974                 } else {
975                         *((gid_t *) p) = strtoul(line, &endptr, 10);
976
977                         /* NOTE: glibc difference - glibc allows omission of the
978                          * trailing colon when there is no member list.  We treat
979                          * this as an error. */
980
981                         /* Make sure we had at least one digit, and that the
982                          * failing char is the next field seperator ':'.  See
983                          * glibc difference note above. */
984                         if ((endptr == line) || (*endptr != ':')) {
985                                 break;
986                         }
987
988                         i = 1;                          /* Count terminating NULL ptr. */
989                         p = endptr;
990
991                         if (p[1]) { /* We have a member list to process. */
992                                 /* Overwrite the last ':' with a ',' before counting.
993                                  * This allows us to test for initial ',' and adds
994                                  * one ',' so that the ',' count equals the member
995                                  * count. */
996                                 *p = ',';
997                                 do {
998                                         /* NOTE: glibc difference - glibc allows and trims leading
999                                          * (but not trailing) space.  We treat this as an error. */
1000                                         /* NOTE: glibc difference - glibc allows consecutive and
1001                                          * trailing commas, and ignores "empty string" users.  We
1002                                          * treat this as an error. */
1003                                         if (*p == ',') {
1004                                                 ++i;
1005                                                 *p = 0; /* nul-terminate each member string. */
1006                                                 if (!*++p || (*p == ',') || isspace(*p)) {
1007                                                         goto ERR;
1008                                                 }
1009                                         }
1010                                 } while (*++p);
1011                         }
1012
1013                         /* Now align (p+1), rounding up. */
1014                         /* Assumes sizeof(char **) is a power of 2. */
1015                         members = (char **)( (((intptr_t) p) + sizeof(char **))
1016                                                                  & ~((intptr_t)(sizeof(char **) - 1)) );
1017
1018                         if (((char *)(members + i)) > end_of_buf) {     /* No space. */
1019                                 break;
1020                         }
1021
1022                         ((struct group *) data)->gr_mem = members;
1023
1024                         if (--i) {
1025                                 p = endptr;     /* Pointing to char prior to first member. */
1026                                 do {
1027                                         *members++ = ++p;
1028                                         if (!--i) break;
1029                                         while (*++p) {}
1030                                 } while (1);
1031                         }
1032                         *members = NULL;
1033
1034                         return 0;
1035                 }
1036         } while (1);
1037
1038  ERR:
1039         return -1;
1040 }
1041
1042 #endif
1043 /**********************************************************************/
1044 #ifdef L___parsespent
1045
1046 static const unsigned char sp_off[] = {
1047         offsetof(struct spwd, sp_namp),         /* 0 */
1048         offsetof(struct spwd, sp_pwdp),         /* 1 */
1049         offsetof(struct spwd, sp_lstchg),       /* 2 - not a char ptr */
1050         offsetof(struct spwd, sp_min),          /* 3 - not a char ptr */
1051         offsetof(struct spwd, sp_max),          /* 4 - not a char ptr */
1052         offsetof(struct spwd, sp_warn),         /* 5 - not a char ptr */
1053         offsetof(struct spwd, sp_inact),        /* 6 - not a char ptr */
1054         offsetof(struct spwd, sp_expire),       /* 7 - not a char ptr */
1055         offsetof(struct spwd, sp_flag)          /* 8 - not a char ptr */
1056 };
1057
1058 int attribute_hidden __parsespent(void *data, char * line)
1059 {
1060         char *endptr;
1061         char *p;
1062         int i;
1063
1064         i = 0;
1065         do {
1066                 p = ((char *) ((struct spwd *) data)) + sp_off[i];
1067                 if (i < 2) {
1068                         *((char **) p) = line;
1069                         if (!(line = strchr(line, ':'))) {
1070                                 break;
1071                         }
1072                 } else {
1073 #if 0
1074                         if (i==5) {                     /* Support for old format. */
1075                                 while (isspace(*line)) ++line; /* glibc eats space here. */
1076                                 if (!*line) {
1077                                         ((struct spwd *) data)->sp_warn = -1;
1078                                         ((struct spwd *) data)->sp_inact = -1;
1079                                         ((struct spwd *) data)->sp_expire = -1;
1080                                         ((struct spwd *) data)->sp_flag = ~0UL;
1081                                         return 0;
1082                                 }
1083                         }
1084 #endif
1085
1086                         *((long *) p) = (long) strtoul(line, &endptr, 10);
1087
1088                         if (endptr == line) {
1089                                 *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
1090                         }
1091
1092                         line = endptr;
1093
1094                         if (i == 8) {
1095                                 if (!*endptr) {
1096                                         return 0;
1097                                 }
1098                                 break;
1099                         }
1100
1101                         if (*endptr != ':') {
1102                                 break;
1103                         }
1104
1105                 }
1106
1107                 *line++ = 0;
1108                 ++i;
1109         } while (1);
1110
1111         return EINVAL;
1112 }
1113
1114 #endif
1115 /**********************************************************************/
1116 #ifdef L___pgsreader
1117
1118 /* Reads until if EOF, or until if finds a line which fits in the buffer
1119  * and for which the parser function succeeds.
1120  *
1121  * Returns 0 on success and ENOENT for end-of-file (glibc concession).
1122  */
1123
1124 int attribute_hidden __pgsreader(int (*__parserfunc)(void *d, char *line), void *data,
1125                                 char *__restrict line_buff, size_t buflen, FILE *f)
1126 {
1127         size_t line_len;
1128         int skip;
1129         int rv = ERANGE;
1130         __STDIO_AUTO_THREADLOCK_VAR;
1131
1132         if (buflen < __UCLIBC_PWD_BUFFER_SIZE__) {
1133                 __set_errno(rv);
1134         } else {
1135                 __STDIO_AUTO_THREADLOCK(f);
1136
1137                 skip = 0;
1138                 do {
1139                         if (!fgets_unlocked(line_buff, buflen, f)) {
1140                                 if (feof_unlocked(f)) {
1141                                         rv = ENOENT;
1142                                 }
1143                                 break;
1144                         }
1145
1146                         line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
1147                         if (line_buff[line_len] == '\n') {
1148                                 line_buff[line_len] = 0;
1149                         } else if (line_len + 2 == buflen) { /* line too long */
1150                                 ++skip;
1151                                 continue;
1152                         }
1153
1154                         if (skip) {
1155                                 --skip;
1156                                 continue;
1157                         }
1158
1159                         /* NOTE: glibc difference - glibc strips leading whitespace from
1160                          * records.  We do not allow leading whitespace. */
1161
1162                         /* Skip empty lines, comment lines, and lines with leading
1163                          * whitespace. */
1164                         if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
1165                                 if (__parserfunc == __parsegrent) {     /* Do evil group hack. */
1166                                         /* The group entry parsing function needs to know where
1167                                          * the end of the buffer is so that it can construct the
1168                                          * group member ptr table. */
1169                                         ((struct group *) data)->gr_name = line_buff + buflen;
1170                                 }
1171
1172                                 if (!__parserfunc(data, line_buff)) {
1173                                         rv = 0;
1174                                         break;
1175                                 }
1176                         }
1177                 } while (1);
1178
1179                 __STDIO_AUTO_THREADUNLOCK(f);
1180         }
1181
1182         return rv;
1183 }
1184
1185 #endif
1186 /**********************************************************************/