New function mu_fgetpwent_r.
* libmailutils/base/fgetpwent.c: Rewrite from scratch. * ChangeLog.amend: Update.
Showing
2 changed files
with
140 additions
and
95 deletions
1 | # Spelling corrections for GNU Mailutils ChangeLog | 1 | # Spelling corrections for GNU Mailutils ChangeLog |
2 | 2 | ||
3 | 89d93a75c4abec10b9cfe0041eaf654d00f0a0ee | ||
4 | s/erad-only/read-only/ | ||
5 | |||
3 | 1cbbd572d56b7a77362992181ef008db8a11688f | 6 | 1cbbd572d56b7a77362992181ef008db8a11688f |
4 | s/consisten/consistent/ | 7 | s/consisten/consistent/ |
5 | 8 | ... | ... |
... | @@ -24,126 +24,165 @@ | ... | @@ -24,126 +24,165 @@ |
24 | #include <pwd.h> | 24 | #include <pwd.h> |
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include <stdlib.h> | 26 | #include <stdlib.h> |
27 | 27 | #include <errno.h> | |
28 | /* | 28 | |
29 | Written by Alain Magloire. | 29 | /* Assuming FP refers to an open file in format of /etc/passwd, read the next |
30 | Simple replacement for fgetpwent(), it is not : | 30 | line and store a pointer to a structure containing the broken-out |
31 | - thread safe; | 31 | fields of the record in the location pointed to by RESULT. Use *BUFP |
32 | - static buffer was not use since it will limit the size | 32 | (of size *BUFS) to store the data, reallocating it if necessary. If |
33 | of the entry. But rather memory is allocated and __never__ | 33 | *BUFP is NULL or *BUFS is 0, allocate new memory. The caller should |
34 | release. The memory will grow if need be. | 34 | free *BUFP when no longer needed. Do not try to free *RESULT! |
35 | - no support for shadow | 35 | |
36 | - no support for NIS(+) | 36 | Input lines not conforming to the /etc/passwd format are silently |
37 | ignored. | ||
38 | |||
39 | Return value: | ||
40 | 0 - success | ||
41 | ENOMEM - not enough memory | ||
42 | ENOENT - no more entries. | ||
37 | */ | 43 | */ |
38 | 44 | ||
39 | static char *buffer; | 45 | int |
40 | static size_t buflen; | 46 | mu_fgetpwent_r (FILE *fp, char **bufp, size_t *bufs, struct passwd **result) |
41 | static struct passwd pw; | ||
42 | |||
43 | static char * | ||
44 | parse_line (char *s, char **p) | ||
45 | { | ||
46 | if (*s) | ||
47 | { | ||
48 | char *sep = strchr (s, ':'); | ||
49 | if (sep) | ||
50 | { | ||
51 | *sep++ = '\0'; | ||
52 | *p = sep; | ||
53 | } | ||
54 | else | ||
55 | *p = s + strlen (s); | ||
56 | } | ||
57 | else | ||
58 | *p = s; | ||
59 | return s; | ||
60 | } | ||
61 | |||
62 | static struct passwd * | ||
63 | getentry (char *s) | ||
64 | { | ||
65 | char *p; | ||
66 | pw.pw_name = parse_line (s, &p); | ||
67 | s = p; | ||
68 | pw.pw_passwd = parse_line (s, &p); | ||
69 | s = p; | ||
70 | pw.pw_uid = strtoul (parse_line (s, &p), NULL, 10); | ||
71 | s = p; | ||
72 | pw.pw_gid = strtoul (parse_line (s, &p), NULL, 10); | ||
73 | s = p; | ||
74 | pw.pw_gecos = parse_line (s, &p); | ||
75 | s = p; | ||
76 | pw.pw_dir = parse_line (s, &p); | ||
77 | s = p; | ||
78 | pw.pw_shell = parse_line (s, &p); | ||
79 | return &pw; | ||
80 | } | ||
81 | |||
82 | struct passwd * | ||
83 | mu_fgetpwent (FILE *fp) | ||
84 | { | 47 | { |
48 | char *buffer = *bufp; | ||
49 | size_t buflen = *bufs; | ||
50 | struct passwd *pwbuf; | ||
85 | size_t pos = 0; | 51 | size_t pos = 0; |
86 | int done = 0; | 52 | int c; |
87 | struct passwd *pw = NULL; | 53 | size_t off[6]; |
54 | int i = 0; | ||
88 | 55 | ||
89 | /* Allocate buffer if not yet available. */ | 56 | if (!buffer) |
90 | /* This buffer will be never free(). */ | 57 | buflen = 0; |
91 | if (buffer == NULL) | ||
92 | { | ||
93 | buflen = 1024; | ||
94 | buffer = malloc (buflen); | ||
95 | if (buffer == NULL) | ||
96 | return NULL; | ||
97 | } | ||
98 | 58 | ||
99 | do | 59 | while ((c = fgetc(fp)) != EOF) |
100 | { | ||
101 | if (fgets (buffer + pos, buflen, fp) != NULL) | ||
102 | { | 60 | { |
103 | /* Need a full line. */ | 61 | if (pos == buflen) |
104 | if (buffer[strlen (buffer) - 1] == '\n') | ||
105 | { | 62 | { |
106 | /* reset marker position. */ | 63 | char *nb; |
107 | pos = 0; | 64 | size_t ns; |
108 | /* Nuke trailing newline. */ | ||
109 | buffer[strlen (buffer) - 1] = '\0'; | ||
110 | 65 | ||
111 | /* Skip comments. */ | 66 | if (buflen == 0) |
112 | if (buffer[0] != '#') | 67 | ns = 128; |
68 | else | ||
113 | { | 69 | { |
114 | done = 1; | 70 | ns = ns * 2; |
115 | pw = getentry (buffer); | 71 | if (ns < buflen) |
72 | return ENOMEM; | ||
116 | } | 73 | } |
74 | nb = realloc(buffer, ns); | ||
75 | if (!nb) | ||
76 | return ENOMEM; | ||
77 | buffer = nb; | ||
78 | buflen = ns; | ||
117 | } | 79 | } |
118 | else | 80 | if (c == '\n') |
119 | { | 81 | { |
120 | /* Line is too long reallocate the buffer. */ | 82 | buffer[pos++] = 0; |
121 | char *tmp; | 83 | if (i != sizeof(off)/sizeof(off[0])) |
122 | pos = strlen (buffer); | 84 | continue; |
123 | buflen *= 2; | 85 | break; |
124 | tmp = realloc (buffer, buflen); | ||
125 | if (tmp) | ||
126 | buffer = tmp; | ||
127 | else | ||
128 | done = 1; | ||
129 | } | 86 | } |
87 | if (c == ':') | ||
88 | { | ||
89 | buffer[pos++] = 0; | ||
90 | if (i < sizeof(off)/sizeof(off[0])) | ||
91 | off[i++] = pos; | ||
130 | } | 92 | } |
131 | else | 93 | else |
132 | done = 1; | 94 | buffer[pos++] = c; |
133 | } while (!done); | 95 | } |
134 | 96 | ||
135 | return pw; | 97 | if (pos == 0) |
98 | return ENOENT; | ||
136 | 99 | ||
100 | if (pos + sizeof(struct passwd) > buflen) | ||
101 | { | ||
102 | char *nb; | ||
103 | size_t ns; | ||
104 | |||
105 | ns = pos + sizeof(struct passwd); | ||
106 | if (ns < buflen) | ||
107 | return ENOMEM; | ||
108 | |||
109 | nb = realloc(buffer, ns); | ||
110 | if (!nb) | ||
111 | return ENOMEM; | ||
112 | buffer = nb; | ||
113 | buflen = ns; | ||
114 | } | ||
115 | pwbuf = (struct passwd*)((char*) buffer + pos); | ||
116 | |||
117 | pwbuf->pw_name = buffer; | ||
118 | pwbuf->pw_passwd = buffer + off[0]; | ||
119 | pwbuf->pw_uid = strtoul(buffer + off[1], NULL, 10); | ||
120 | pwbuf->pw_gid = strtoul(buffer + off[2], NULL, 10); | ||
121 | pwbuf->pw_gecos = buffer + off[3]; | ||
122 | pwbuf->pw_dir = buffer + off[4]; | ||
123 | pwbuf->pw_shell = buffer + off[5]; | ||
124 | |||
125 | *bufp = buffer; | ||
126 | *bufs = buflen; | ||
127 | *result = pwbuf; | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | /* A simple replacement for fgetpwent(). | ||
132 | Note: | ||
133 | - it is not thread safe (neither is the original fgetpwent) | ||
134 | - uses dynamically allocated buffer that is __never__ freed. | ||
135 | - no support for shadow nor BSD-style pwddb (neither has the original | ||
136 | fgetpwent). | ||
137 | - no support for NIS(+). | ||
138 | |||
139 | Initial implementation by Alain Magloire. | ||
140 | Rewritten from scratch by Sergey Poznyakoff. | ||
141 | */ | ||
142 | struct passwd * | ||
143 | mu_fgetpwent (FILE *fp) | ||
144 | { | ||
145 | static char *buffer; | ||
146 | static size_t bufsize; | ||
147 | static struct passwd *pwbuf; | ||
148 | int rc = mu_fgetpwent_r (fp, &buffer, &bufsize, &pwbuf); | ||
149 | if (rc) | ||
150 | { | ||
151 | errno = rc; | ||
152 | return NULL; | ||
153 | } | ||
154 | return pwbuf; | ||
137 | } | 155 | } |
138 | 156 | ||
139 | #ifdef STANDALONE | 157 | #ifdef STANDALONE |
158 | # include <assert.h> | ||
159 | |||
140 | int | 160 | int |
141 | main () | 161 | main (int argc, char **argv) |
142 | { | 162 | { |
143 | FILE *fp = fopen ("/etc/passwd", "r"); | 163 | FILE *fp; |
144 | if (fp) | 164 | |
165 | if (argc == 1) | ||
166 | { | ||
167 | char *a[3]; | ||
168 | a[0] = argv[0]; | ||
169 | a[1] = "/etc/passwd"; | ||
170 | a[2] = NULL; | ||
171 | argv = a; | ||
172 | argc = 2; | ||
173 | } | ||
174 | while (--argc) | ||
145 | { | 175 | { |
146 | struct passwd *pwd; | 176 | struct passwd *pwd; |
177 | char *file = *++argv; | ||
178 | |||
179 | fp = fopen (file, "r"); | ||
180 | if (!fp) | ||
181 | { | ||
182 | perror (file); | ||
183 | continue; | ||
184 | } | ||
185 | printf ("Reading %s\n", file); | ||
147 | while ((pwd = fgetpwent (fp))) | 186 | while ((pwd = fgetpwent (fp))) |
148 | { | 187 | { |
149 | printf ("--------------------------------------\n"); | 188 | printf ("--------------------------------------\n"); |
... | @@ -155,6 +194,9 @@ main () | ... | @@ -155,6 +194,9 @@ main () |
155 | printf ("dir %s\n", pwd->pw_dir); | 194 | printf ("dir %s\n", pwd->pw_dir); |
156 | printf ("shell %s\n", pwd->pw_shell); | 195 | printf ("shell %s\n", pwd->pw_shell); |
157 | } | 196 | } |
197 | printf ("======================================\n"); | ||
198 | printf ("End of %s\n", file); | ||
199 | close (fp); | ||
158 | } | 200 | } |
159 | return 0; | 201 | return 0; |
160 | } | 202 | } | ... | ... |
-
Please register or sign in to post a comment