-
-int putpwent(const struct passwd *__restrict p, FILE *__restrict f)
-{
- int rv = -1;
-
- if (!p || !f) {
- errno = EINVAL;
- } else {
- /* No extra thread locking is needed above what fprintf does. */
- if (fprintf(f, "%s:%s:%lu:%lu:%s:%s:%s\n",
- p->pw_name, p->pw_passwd,
- (unsigned long)(p->pw_uid),
- (unsigned long)(p->pw_gid),
- p->pw_gecos, p->pw_dir, p->pw_shell) >= 0
- ) {
- rv = 0;
- }
- }
-
- return rv;
-}
-
-int putgrent(const struct group *__restrict p, FILE *__restrict f)
-{
- static const char format[] ALIGN1 = ",%s";
-
- char **m;
- const char *fmt;
- int rv = -1;
-
- if (!p || !f) { /* Sigh... glibc checks. */
- errno = EINVAL;
- } else {
- if (fprintf(f, "%s:%s:%lu:",
- p->gr_name, p->gr_passwd,
- (unsigned long)(p->gr_gid)) >= 0
- ) {
-
- fmt = format + 1;
-
- assert(p->gr_mem);
- m = p->gr_mem;
-
- do {
- if (!*m) {
- if (fputc('\n', f) >= 0) {
- rv = 0;
- }
- break;
- }
- if (fprintf(f, fmt, *m) < 0) {
- break;
- }
- ++m;
- fmt = format;
- } while (1);
-
- }
-
- }
-
- return rv;
-}
-
-#if ENABLE_USE_BB_SHADOW
-static const unsigned char _sp_off[] ALIGN1 = {
- offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
- offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
- offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
- offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
- offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
- offsetof(struct spwd, sp_expire) /* 7 - not a char ptr */
-};
-
-int putspent(const struct spwd *p, FILE *stream)
-{
- static const char ld_format[] ALIGN1 = "%ld:";
-
- const char *f;
- long x;
- int i;
- int rv = -1;
-
- /* Unlike putpwent and putgrent, glibc does not check the args. */
- if (fprintf(stream, "%s:%s:", p->sp_namp,
- (p->sp_pwdp ? p->sp_pwdp : "")) < 0
- ) {
- goto DO_UNLOCK;
- }
-
- for (i = 0; i < sizeof(_sp_off); i++) {
- f = ld_format;
- x = *(const long *)(((const char *) p) + _sp_off[i]);
- if (x == -1) {
- f += 3;
- }
- if (fprintf(stream, f, x) < 0) {
- goto DO_UNLOCK;
- }
- }
-
- if ((p->sp_flag != ~0UL) && (fprintf(stream, "%lu", p->sp_flag) < 0)) {
- goto DO_UNLOCK;
- }
-
- if (fputc('\n', stream) > 0) {
- rv = 0;
- }
-
-DO_UNLOCK:
- return rv;
-}
-#endif
-
-/**********************************************************************/
-/* Internal uClibc functions. */
-/**********************************************************************/
-
-static const unsigned char pw_off[] ALIGN1 = {
- offsetof(struct passwd, pw_name), /* 0 */
- offsetof(struct passwd, pw_passwd), /* 1 */
- offsetof(struct passwd, pw_uid), /* 2 - not a char ptr */
- offsetof(struct passwd, pw_gid), /* 3 - not a char ptr */
- offsetof(struct passwd, pw_gecos), /* 4 */
- offsetof(struct passwd, pw_dir), /* 5 */
- offsetof(struct passwd, pw_shell) /* 6 */
-};
-
-static int bb__parsepwent(void *data, char *line)
-{
- char *endptr;
- char *p;
- int i;
-
- i = 0;
- do {
- p = ((char *) ((struct passwd *) data)) + pw_off[i];
-
- if ((i & 6) ^ 2) { /* i!=2 and i!=3 */
- *((char **) p) = line;
- if (i==6) {
- return 0;
- }
- /* NOTE: glibc difference - glibc allows omission of
- * ':' seperators after the gid field if all remaining
- * entries are empty. We require all separators. */
- line = strchr(line, ':');
- if (!line) {
- break;
- }
- } else {
- unsigned long t = strtoul(line, &endptr, 10);
- /* Make sure we had at least one digit, and that the
- * failing char is the next field seperator ':'. See
- * glibc difference note above. */
- /* TODO: Also check for leading whitespace? */
- if ((endptr == line) || (*endptr != ':')) {
- break;
- }
- line = endptr;
- if (i & 1) { /* i == 3 -- gid */
- *((gid_t *) p) = t;
- } else { /* i == 2 -- uid */
- *((uid_t *) p) = t;
- }
- }
-
- *line++ = 0;
- ++i;
- } while (1);
-
- return -1;
-}
-
-/**********************************************************************/
-
-static const unsigned char gr_off[] ALIGN1 = {
- offsetof(struct group, gr_name), /* 0 */
- offsetof(struct group, gr_passwd), /* 1 */
- offsetof(struct group, gr_gid) /* 2 - not a char ptr */
-};
-
-static int bb__parsegrent(void *data, char *line)
-{
- char *endptr;
- char *p;
- int i;
- char **members;
- char *end_of_buf;
-
- end_of_buf = ((struct group *) data)->gr_name; /* Evil hack! */
- i = 0;
- do {
- p = ((char *) ((struct group *) data)) + gr_off[i];
-
- if (i < 2) {
- *((char **) p) = line;
- line = strchr(line, ':');
- if (!line) {
- break;
- }
- *line++ = 0;
- ++i;
- } else {
- *((gid_t *) p) = strtoul(line, &endptr, 10);
-
- /* NOTE: glibc difference - glibc allows omission of the
- * trailing colon when there is no member list. We treat
- * this as an error. */
-
- /* Make sure we had at least one digit, and that the
- * failing char is the next field seperator ':'. See
- * glibc difference note above. */
- if ((endptr == line) || (*endptr != ':')) {
- break;
- }
-
- i = 1; /* Count terminating NULL ptr. */
- p = endptr;
-
- if (p[1]) { /* We have a member list to process. */
- /* Overwrite the last ':' with a ',' before counting.
- * This allows us to test for initial ',' and adds
- * one ',' so that the ',' count equals the member
- * count. */
- *p = ',';
- do {
- /* NOTE: glibc difference - glibc allows and trims leading
- * (but not trailing) space. We treat this as an error. */
- /* NOTE: glibc difference - glibc allows consecutive and
- * trailing commas, and ignores "empty string" users. We
- * treat this as an error. */
- if (*p == ',') {
- ++i;
- *p = 0; /* nul-terminate each member string. */
- if (!*++p || (*p == ',') || isspace(*p)) {
- goto ERR;
- }
- }
- } while (*++p);
- }
-
- /* Now align (p+1), rounding up. */
- /* Assumes sizeof(char **) is a power of 2. */
- members = (char **)( (((intptr_t) p) + sizeof(char **))
- & ~((intptr_t)(sizeof(char **) - 1)) );
-
- if (((char *)(members + i)) > end_of_buf) { /* No space. */
- break;
- }
-
- ((struct group *) data)->gr_mem = members;
-
- if (--i) {
- p = endptr; /* Pointing to char prior to first member. */
- do {
- *members++ = ++p;
- if (!--i) break;
- while (*++p) {}
- } while (1);
- }
- *members = NULL;
-
- return 0;
- }
- } while (1);
-
- ERR:
- return -1;
-}
-
-/**********************************************************************/
-
-#if ENABLE_USE_BB_SHADOW
-static const unsigned char sp_off[] ALIGN1 = {
- offsetof(struct spwd, sp_namp), /* 0 */
- offsetof(struct spwd, sp_pwdp), /* 1 */
- offsetof(struct spwd, sp_lstchg), /* 2 - not a char ptr */
- offsetof(struct spwd, sp_min), /* 3 - not a char ptr */
- offsetof(struct spwd, sp_max), /* 4 - not a char ptr */
- offsetof(struct spwd, sp_warn), /* 5 - not a char ptr */
- offsetof(struct spwd, sp_inact), /* 6 - not a char ptr */
- offsetof(struct spwd, sp_expire), /* 7 - not a char ptr */
- offsetof(struct spwd, sp_flag) /* 8 - not a char ptr */
-};
-
-static int bb__parsespent(void *data, char * line)
-{
- char *endptr;
- char *p;
- int i;
-
- i = 0;
- do {
- p = ((char *) ((struct spwd *) data)) + sp_off[i];
- if (i < 2) {
- *((char **) p) = line;
- line = strchr(line, ':');
- if (!line) {
- break;
- }
- } else {
- *((long *) p) = (long) strtoul(line, &endptr, 10);
-
- if (endptr == line) {
- *((long *) p) = ((i != 8) ? -1L : ((long)(~0UL)));
- }
-
- line = endptr;
-
- if (i == 8) {
- if (!*endptr) {
- return 0;
- }
- break;
- }
-
- if (*endptr != ':') {
- break;
- }
-
- }
-
- *line++ = 0;
- ++i;
- } while (1);
-
- return EINVAL;
-}
-#endif
-
-/**********************************************************************/
-
-/* Reads until if EOF, or until if finds a line which fits in the buffer
- * and for which the parser function succeeds.
- *
- * Returns 0 on success and ENOENT for end-of-file (glibc concession).
- */
-
-static int bb__pgsreader(int (*parserfunc)(void *d, char *line), void *data,
- char *__restrict line_buff, size_t buflen, FILE *f)
-{
- int line_len;
- int skip;
- int rv = ERANGE;
-
- if (buflen < PWD_BUFFER_SIZE) {
- errno = rv;
- } else {
- skip = 0;
- do {
- if (!fgets(line_buff, buflen, f)) {
- if (feof(f)) {
- rv = ENOENT;
- }
- break;
- }
-
- line_len = strlen(line_buff) - 1; /* strlen() must be > 0. */
- if (line_buff[line_len] == '\n') {
- line_buff[line_len] = 0;
- } else if (line_len + 2 == buflen) { /* line too long */
- ++skip;
- continue;
- }
-
- if (skip) {
- --skip;
- continue;
- }
-
- /* NOTE: glibc difference - glibc strips leading whitespace from
- * records. We do not allow leading whitespace. */
-
- /* Skip empty lines, comment lines, and lines with leading
- * whitespace. */
- if (*line_buff && (*line_buff != '#') && !isspace(*line_buff)) {
- if (parserfunc == bb__parsegrent) { /* Do evil group hack. */
- /* The group entry parsing function needs to know where
- * the end of the buffer is so that it can construct the
- * group member ptr table. */
- ((struct group *) data)->gr_name = line_buff + buflen;
- }
-
- if (!parserfunc(data, line_buff)) {
- rv = 0;
- break;
- }
- }
- } while (1);
-
- }
-
- return rv;
-}