Commit d0590302 d0590302f3bde188c5548c06538df7b172f12521 by Sergey Poznyakoff

New function mu_fgetpwent_r.

* libmailutils/base/fgetpwent.c: Rewrite from scratch.
* ChangeLog.amend: Update.
1 parent 751aad90
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 }
......