xref: /aosp_15_r20/external/kmod/libkmod/libkmod-builtin.c (revision cc4ad7da8cefe208cb129ac2aa9a357c7c72deb2)
1*cc4ad7daSAndroid Build Coastguard Worker /*
2*cc4ad7daSAndroid Build Coastguard Worker  * libkmod - interface to kernel built-in modules
3*cc4ad7daSAndroid Build Coastguard Worker  *
4*cc4ad7daSAndroid Build Coastguard Worker  * Copyright (C) 2019  Alexey Gladkov <[email protected]>
5*cc4ad7daSAndroid Build Coastguard Worker  *
6*cc4ad7daSAndroid Build Coastguard Worker  * This library is free software; you can redistribute it and/or
7*cc4ad7daSAndroid Build Coastguard Worker  * modify it under the terms of the GNU Lesser General Public
8*cc4ad7daSAndroid Build Coastguard Worker  * License as published by the Free Software Foundation; either
9*cc4ad7daSAndroid Build Coastguard Worker  * version 2.1 of the License, or (at your option) any later version.
10*cc4ad7daSAndroid Build Coastguard Worker  *
11*cc4ad7daSAndroid Build Coastguard Worker  * This library is distributed in the hope that it will be useful,
12*cc4ad7daSAndroid Build Coastguard Worker  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13*cc4ad7daSAndroid Build Coastguard Worker  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14*cc4ad7daSAndroid Build Coastguard Worker  * Lesser General Public License for more details.
15*cc4ad7daSAndroid Build Coastguard Worker  *
16*cc4ad7daSAndroid Build Coastguard Worker  * You should have received a copy of the GNU Lesser General Public
17*cc4ad7daSAndroid Build Coastguard Worker  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18*cc4ad7daSAndroid Build Coastguard Worker  */
19*cc4ad7daSAndroid Build Coastguard Worker 
20*cc4ad7daSAndroid Build Coastguard Worker #include <sys/types.h>
21*cc4ad7daSAndroid Build Coastguard Worker #include <sys/stat.h>
22*cc4ad7daSAndroid Build Coastguard Worker 
23*cc4ad7daSAndroid Build Coastguard Worker #include <unistd.h>
24*cc4ad7daSAndroid Build Coastguard Worker #include <stdio.h>
25*cc4ad7daSAndroid Build Coastguard Worker #include <stdlib.h>
26*cc4ad7daSAndroid Build Coastguard Worker #include <string.h>
27*cc4ad7daSAndroid Build Coastguard Worker #include <errno.h>
28*cc4ad7daSAndroid Build Coastguard Worker 
29*cc4ad7daSAndroid Build Coastguard Worker #include "libkmod.h"
30*cc4ad7daSAndroid Build Coastguard Worker #include "libkmod-internal.h"
31*cc4ad7daSAndroid Build Coastguard Worker 
32*cc4ad7daSAndroid Build Coastguard Worker #define MODULES_BUILTIN_MODINFO "modules.builtin.modinfo"
33*cc4ad7daSAndroid Build Coastguard Worker 
34*cc4ad7daSAndroid Build Coastguard Worker struct kmod_builtin_iter {
35*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_ctx *ctx;
36*cc4ad7daSAndroid Build Coastguard Worker 
37*cc4ad7daSAndroid Build Coastguard Worker 	// The file descriptor.
38*cc4ad7daSAndroid Build Coastguard Worker 	int file;
39*cc4ad7daSAndroid Build Coastguard Worker 
40*cc4ad7daSAndroid Build Coastguard Worker 	// The total size in bytes.
41*cc4ad7daSAndroid Build Coastguard Worker 	ssize_t size;
42*cc4ad7daSAndroid Build Coastguard Worker 
43*cc4ad7daSAndroid Build Coastguard Worker 	// The offset of current module.
44*cc4ad7daSAndroid Build Coastguard Worker 	off_t pos;
45*cc4ad7daSAndroid Build Coastguard Worker 
46*cc4ad7daSAndroid Build Coastguard Worker 	// The offset at which the next module is located.
47*cc4ad7daSAndroid Build Coastguard Worker 	off_t next;
48*cc4ad7daSAndroid Build Coastguard Worker 
49*cc4ad7daSAndroid Build Coastguard Worker 	// Number of strings in the current block.
50*cc4ad7daSAndroid Build Coastguard Worker 	ssize_t nstrings;
51*cc4ad7daSAndroid Build Coastguard Worker 
52*cc4ad7daSAndroid Build Coastguard Worker 	// Internal buffer and its size.
53*cc4ad7daSAndroid Build Coastguard Worker 	size_t bufsz;
54*cc4ad7daSAndroid Build Coastguard Worker 	char *buf;
55*cc4ad7daSAndroid Build Coastguard Worker };
56*cc4ad7daSAndroid Build Coastguard Worker 
kmod_builtin_iter_new(struct kmod_ctx * ctx)57*cc4ad7daSAndroid Build Coastguard Worker static struct kmod_builtin_iter *kmod_builtin_iter_new(struct kmod_ctx *ctx)
58*cc4ad7daSAndroid Build Coastguard Worker {
59*cc4ad7daSAndroid Build Coastguard Worker 	char path[PATH_MAX];
60*cc4ad7daSAndroid Build Coastguard Worker 	int file, sv_errno;
61*cc4ad7daSAndroid Build Coastguard Worker 	struct stat sb;
62*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_builtin_iter *iter = NULL;
63*cc4ad7daSAndroid Build Coastguard Worker 	const char *dirname = kmod_get_dirname(ctx);
64*cc4ad7daSAndroid Build Coastguard Worker 	size_t len = strlen(dirname);
65*cc4ad7daSAndroid Build Coastguard Worker 
66*cc4ad7daSAndroid Build Coastguard Worker 	file = -1;
67*cc4ad7daSAndroid Build Coastguard Worker 
68*cc4ad7daSAndroid Build Coastguard Worker 	if ((len + 1 + strlen(MODULES_BUILTIN_MODINFO) + 1) >= PATH_MAX) {
69*cc4ad7daSAndroid Build Coastguard Worker 		sv_errno = ENAMETOOLONG;
70*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
71*cc4ad7daSAndroid Build Coastguard Worker 	}
72*cc4ad7daSAndroid Build Coastguard Worker 
73*cc4ad7daSAndroid Build Coastguard Worker 	snprintf(path, PATH_MAX, "%s/%s", dirname, MODULES_BUILTIN_MODINFO);
74*cc4ad7daSAndroid Build Coastguard Worker 
75*cc4ad7daSAndroid Build Coastguard Worker 	file = open(path, O_RDONLY|O_CLOEXEC);
76*cc4ad7daSAndroid Build Coastguard Worker 	if (file < 0) {
77*cc4ad7daSAndroid Build Coastguard Worker 		sv_errno = errno;
78*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
79*cc4ad7daSAndroid Build Coastguard Worker 	}
80*cc4ad7daSAndroid Build Coastguard Worker 
81*cc4ad7daSAndroid Build Coastguard Worker 	if (fstat(file, &sb) < 0) {
82*cc4ad7daSAndroid Build Coastguard Worker 		sv_errno = errno;
83*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
84*cc4ad7daSAndroid Build Coastguard Worker 	}
85*cc4ad7daSAndroid Build Coastguard Worker 
86*cc4ad7daSAndroid Build Coastguard Worker 	iter = malloc(sizeof(*iter));
87*cc4ad7daSAndroid Build Coastguard Worker 	if (!iter) {
88*cc4ad7daSAndroid Build Coastguard Worker 		sv_errno = ENOMEM;
89*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
90*cc4ad7daSAndroid Build Coastguard Worker 	}
91*cc4ad7daSAndroid Build Coastguard Worker 
92*cc4ad7daSAndroid Build Coastguard Worker 	iter->ctx = ctx;
93*cc4ad7daSAndroid Build Coastguard Worker 	iter->file = file;
94*cc4ad7daSAndroid Build Coastguard Worker 	iter->size = sb.st_size;
95*cc4ad7daSAndroid Build Coastguard Worker 	iter->nstrings = 0;
96*cc4ad7daSAndroid Build Coastguard Worker 	iter->pos = 0;
97*cc4ad7daSAndroid Build Coastguard Worker 	iter->next = 0;
98*cc4ad7daSAndroid Build Coastguard Worker 	iter->bufsz = 0;
99*cc4ad7daSAndroid Build Coastguard Worker 	iter->buf = NULL;
100*cc4ad7daSAndroid Build Coastguard Worker 
101*cc4ad7daSAndroid Build Coastguard Worker 	return iter;
102*cc4ad7daSAndroid Build Coastguard Worker fail:
103*cc4ad7daSAndroid Build Coastguard Worker 	if (file >= 0)
104*cc4ad7daSAndroid Build Coastguard Worker 		close(file);
105*cc4ad7daSAndroid Build Coastguard Worker 
106*cc4ad7daSAndroid Build Coastguard Worker 	errno = sv_errno;
107*cc4ad7daSAndroid Build Coastguard Worker 
108*cc4ad7daSAndroid Build Coastguard Worker 	return iter;
109*cc4ad7daSAndroid Build Coastguard Worker }
110*cc4ad7daSAndroid Build Coastguard Worker 
kmod_builtin_iter_free(struct kmod_builtin_iter * iter)111*cc4ad7daSAndroid Build Coastguard Worker static void kmod_builtin_iter_free(struct kmod_builtin_iter *iter)
112*cc4ad7daSAndroid Build Coastguard Worker {
113*cc4ad7daSAndroid Build Coastguard Worker 	close(iter->file);
114*cc4ad7daSAndroid Build Coastguard Worker 	free(iter->buf);
115*cc4ad7daSAndroid Build Coastguard Worker 	free(iter);
116*cc4ad7daSAndroid Build Coastguard Worker }
117*cc4ad7daSAndroid Build Coastguard Worker 
get_string(struct kmod_builtin_iter * iter,off_t offset,char ** line,size_t * size)118*cc4ad7daSAndroid Build Coastguard Worker static off_t get_string(struct kmod_builtin_iter *iter, off_t offset,
119*cc4ad7daSAndroid Build Coastguard Worker 			char **line, size_t *size)
120*cc4ad7daSAndroid Build Coastguard Worker {
121*cc4ad7daSAndroid Build Coastguard Worker 	int sv_errno;
122*cc4ad7daSAndroid Build Coastguard Worker 	char *nullp = NULL;
123*cc4ad7daSAndroid Build Coastguard Worker 	size_t linesz = 0;
124*cc4ad7daSAndroid Build Coastguard Worker 
125*cc4ad7daSAndroid Build Coastguard Worker 	while (!nullp) {
126*cc4ad7daSAndroid Build Coastguard Worker 		char buf[BUFSIZ];
127*cc4ad7daSAndroid Build Coastguard Worker 		ssize_t sz;
128*cc4ad7daSAndroid Build Coastguard Worker 		size_t partsz;
129*cc4ad7daSAndroid Build Coastguard Worker 
130*cc4ad7daSAndroid Build Coastguard Worker 		sz = pread(iter->file, buf, BUFSIZ, offset);
131*cc4ad7daSAndroid Build Coastguard Worker 		if (sz < 0) {
132*cc4ad7daSAndroid Build Coastguard Worker 			sv_errno = errno;
133*cc4ad7daSAndroid Build Coastguard Worker 			goto fail;
134*cc4ad7daSAndroid Build Coastguard Worker 		} else if (sz == 0) {
135*cc4ad7daSAndroid Build Coastguard Worker 			offset = 0;
136*cc4ad7daSAndroid Build Coastguard Worker 			break;
137*cc4ad7daSAndroid Build Coastguard Worker 		}
138*cc4ad7daSAndroid Build Coastguard Worker 
139*cc4ad7daSAndroid Build Coastguard Worker 		nullp = memchr(buf, '\0', (size_t) sz);
140*cc4ad7daSAndroid Build Coastguard Worker 		partsz = (size_t)((nullp) ? (nullp - buf) + 1 : sz);
141*cc4ad7daSAndroid Build Coastguard Worker 		offset += (off_t) partsz;
142*cc4ad7daSAndroid Build Coastguard Worker 
143*cc4ad7daSAndroid Build Coastguard Worker 		if (iter->bufsz < linesz + partsz) {
144*cc4ad7daSAndroid Build Coastguard Worker 			iter->bufsz = linesz + partsz;
145*cc4ad7daSAndroid Build Coastguard Worker 			iter->buf = realloc(iter->buf, iter->bufsz);
146*cc4ad7daSAndroid Build Coastguard Worker 
147*cc4ad7daSAndroid Build Coastguard Worker 			if (!iter->buf) {
148*cc4ad7daSAndroid Build Coastguard Worker 				sv_errno = errno;
149*cc4ad7daSAndroid Build Coastguard Worker 				goto fail;
150*cc4ad7daSAndroid Build Coastguard Worker 			}
151*cc4ad7daSAndroid Build Coastguard Worker 		}
152*cc4ad7daSAndroid Build Coastguard Worker 
153*cc4ad7daSAndroid Build Coastguard Worker 		strncpy(iter->buf + linesz, buf, partsz);
154*cc4ad7daSAndroid Build Coastguard Worker 		linesz += partsz;
155*cc4ad7daSAndroid Build Coastguard Worker 	}
156*cc4ad7daSAndroid Build Coastguard Worker 
157*cc4ad7daSAndroid Build Coastguard Worker 	if (linesz) {
158*cc4ad7daSAndroid Build Coastguard Worker 		*line = iter->buf;
159*cc4ad7daSAndroid Build Coastguard Worker 		*size = linesz;
160*cc4ad7daSAndroid Build Coastguard Worker 	}
161*cc4ad7daSAndroid Build Coastguard Worker 
162*cc4ad7daSAndroid Build Coastguard Worker 	return offset;
163*cc4ad7daSAndroid Build Coastguard Worker fail:
164*cc4ad7daSAndroid Build Coastguard Worker 	errno = sv_errno;
165*cc4ad7daSAndroid Build Coastguard Worker 	return -1;
166*cc4ad7daSAndroid Build Coastguard Worker }
167*cc4ad7daSAndroid Build Coastguard Worker 
kmod_builtin_iter_next(struct kmod_builtin_iter * iter)168*cc4ad7daSAndroid Build Coastguard Worker static bool kmod_builtin_iter_next(struct kmod_builtin_iter *iter)
169*cc4ad7daSAndroid Build Coastguard Worker {
170*cc4ad7daSAndroid Build Coastguard Worker 	char *line,  *modname;
171*cc4ad7daSAndroid Build Coastguard Worker 	size_t linesz;
172*cc4ad7daSAndroid Build Coastguard Worker 	off_t pos, offset, modlen;
173*cc4ad7daSAndroid Build Coastguard Worker 
174*cc4ad7daSAndroid Build Coastguard Worker 	modname = NULL;
175*cc4ad7daSAndroid Build Coastguard Worker 
176*cc4ad7daSAndroid Build Coastguard Worker 	iter->nstrings = 0;
177*cc4ad7daSAndroid Build Coastguard Worker 	offset = pos = iter->next;
178*cc4ad7daSAndroid Build Coastguard Worker 
179*cc4ad7daSAndroid Build Coastguard Worker 	while (offset < iter->size) {
180*cc4ad7daSAndroid Build Coastguard Worker 		char *dot;
181*cc4ad7daSAndroid Build Coastguard Worker 		off_t len;
182*cc4ad7daSAndroid Build Coastguard Worker 
183*cc4ad7daSAndroid Build Coastguard Worker 		offset = get_string(iter, pos, &line, &linesz);
184*cc4ad7daSAndroid Build Coastguard Worker 		if (offset <= 0) {
185*cc4ad7daSAndroid Build Coastguard Worker 			if (offset)
186*cc4ad7daSAndroid Build Coastguard Worker 				ERR(iter->ctx, "get_string: %s\n", strerror(errno));
187*cc4ad7daSAndroid Build Coastguard Worker 			pos = iter->size;
188*cc4ad7daSAndroid Build Coastguard Worker 			break;
189*cc4ad7daSAndroid Build Coastguard Worker 		}
190*cc4ad7daSAndroid Build Coastguard Worker 
191*cc4ad7daSAndroid Build Coastguard Worker 		dot = strchr(line, '.');
192*cc4ad7daSAndroid Build Coastguard Worker 		if (!dot) {
193*cc4ad7daSAndroid Build Coastguard Worker 			ERR(iter->ctx, "kmod_builtin_iter_next: unexpected string without modname prefix\n");
194*cc4ad7daSAndroid Build Coastguard Worker 			pos = iter->size;
195*cc4ad7daSAndroid Build Coastguard Worker 			break;
196*cc4ad7daSAndroid Build Coastguard Worker 		}
197*cc4ad7daSAndroid Build Coastguard Worker 
198*cc4ad7daSAndroid Build Coastguard Worker 		len = dot - line;
199*cc4ad7daSAndroid Build Coastguard Worker 
200*cc4ad7daSAndroid Build Coastguard Worker 		if (!modname) {
201*cc4ad7daSAndroid Build Coastguard Worker 			modname = strdup(line);
202*cc4ad7daSAndroid Build Coastguard Worker 			modlen = len;
203*cc4ad7daSAndroid Build Coastguard Worker 		} else if (modlen != len || strncmp(modname, line, len)) {
204*cc4ad7daSAndroid Build Coastguard Worker 			break;
205*cc4ad7daSAndroid Build Coastguard Worker 		}
206*cc4ad7daSAndroid Build Coastguard Worker 
207*cc4ad7daSAndroid Build Coastguard Worker 		iter->nstrings++;
208*cc4ad7daSAndroid Build Coastguard Worker 		pos = offset;
209*cc4ad7daSAndroid Build Coastguard Worker 	}
210*cc4ad7daSAndroid Build Coastguard Worker 
211*cc4ad7daSAndroid Build Coastguard Worker 	iter->pos = iter->next;
212*cc4ad7daSAndroid Build Coastguard Worker 	iter->next = pos;
213*cc4ad7daSAndroid Build Coastguard Worker 
214*cc4ad7daSAndroid Build Coastguard Worker 	free(modname);
215*cc4ad7daSAndroid Build Coastguard Worker 
216*cc4ad7daSAndroid Build Coastguard Worker 	return (iter->pos < iter->size);
217*cc4ad7daSAndroid Build Coastguard Worker }
218*cc4ad7daSAndroid Build Coastguard Worker 
kmod_builtin_iter_get_modname(struct kmod_builtin_iter * iter,char modname[static PATH_MAX])219*cc4ad7daSAndroid Build Coastguard Worker static bool kmod_builtin_iter_get_modname(struct kmod_builtin_iter *iter,
220*cc4ad7daSAndroid Build Coastguard Worker 				char modname[static PATH_MAX])
221*cc4ad7daSAndroid Build Coastguard Worker {
222*cc4ad7daSAndroid Build Coastguard Worker 	int sv_errno;
223*cc4ad7daSAndroid Build Coastguard Worker 	char *line, *dot;
224*cc4ad7daSAndroid Build Coastguard Worker 	size_t linesz, len;
225*cc4ad7daSAndroid Build Coastguard Worker 	off_t offset;
226*cc4ad7daSAndroid Build Coastguard Worker 
227*cc4ad7daSAndroid Build Coastguard Worker 	if (iter->pos == iter->size)
228*cc4ad7daSAndroid Build Coastguard Worker 		return false;
229*cc4ad7daSAndroid Build Coastguard Worker 
230*cc4ad7daSAndroid Build Coastguard Worker 	line = NULL;
231*cc4ad7daSAndroid Build Coastguard Worker 
232*cc4ad7daSAndroid Build Coastguard Worker 	offset = get_string(iter, iter->pos, &line, &linesz);
233*cc4ad7daSAndroid Build Coastguard Worker 	if (offset <= 0) {
234*cc4ad7daSAndroid Build Coastguard Worker 		sv_errno = errno;
235*cc4ad7daSAndroid Build Coastguard Worker 		if (offset)
236*cc4ad7daSAndroid Build Coastguard Worker 			ERR(iter->ctx, "get_string: %s\n", strerror(errno));
237*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
238*cc4ad7daSAndroid Build Coastguard Worker 	}
239*cc4ad7daSAndroid Build Coastguard Worker 
240*cc4ad7daSAndroid Build Coastguard Worker 	dot = strchr(line, '.');
241*cc4ad7daSAndroid Build Coastguard Worker 	if (!dot) {
242*cc4ad7daSAndroid Build Coastguard Worker 		sv_errno = errno;
243*cc4ad7daSAndroid Build Coastguard Worker 		ERR(iter->ctx, "kmod_builtin_iter_get_modname: unexpected string without modname prefix\n");
244*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
245*cc4ad7daSAndroid Build Coastguard Worker 	}
246*cc4ad7daSAndroid Build Coastguard Worker 
247*cc4ad7daSAndroid Build Coastguard Worker 	len = dot - line;
248*cc4ad7daSAndroid Build Coastguard Worker 
249*cc4ad7daSAndroid Build Coastguard Worker 	if (len >= PATH_MAX) {
250*cc4ad7daSAndroid Build Coastguard Worker 		sv_errno = ENAMETOOLONG;
251*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
252*cc4ad7daSAndroid Build Coastguard Worker 	}
253*cc4ad7daSAndroid Build Coastguard Worker 
254*cc4ad7daSAndroid Build Coastguard Worker 	strncpy(modname, line, len);
255*cc4ad7daSAndroid Build Coastguard Worker 	modname[len] = '\0';
256*cc4ad7daSAndroid Build Coastguard Worker 
257*cc4ad7daSAndroid Build Coastguard Worker 	return true;
258*cc4ad7daSAndroid Build Coastguard Worker fail:
259*cc4ad7daSAndroid Build Coastguard Worker 	errno = sv_errno;
260*cc4ad7daSAndroid Build Coastguard Worker 	return false;
261*cc4ad7daSAndroid Build Coastguard Worker }
262*cc4ad7daSAndroid Build Coastguard Worker 
263*cc4ad7daSAndroid Build Coastguard Worker /* array will be allocated with strings in a single malloc, just free *array */
kmod_builtin_get_modinfo(struct kmod_ctx * ctx,const char * modname,char *** modinfo)264*cc4ad7daSAndroid Build Coastguard Worker ssize_t kmod_builtin_get_modinfo(struct kmod_ctx *ctx, const char *modname,
265*cc4ad7daSAndroid Build Coastguard Worker 				char ***modinfo)
266*cc4ad7daSAndroid Build Coastguard Worker {
267*cc4ad7daSAndroid Build Coastguard Worker 	ssize_t count = 0;
268*cc4ad7daSAndroid Build Coastguard Worker 	char *s, *line = NULL;
269*cc4ad7daSAndroid Build Coastguard Worker 	size_t i, n, linesz, modlen, size;
270*cc4ad7daSAndroid Build Coastguard Worker 	off_t pos, offset;
271*cc4ad7daSAndroid Build Coastguard Worker 
272*cc4ad7daSAndroid Build Coastguard Worker 	char *name = NULL;
273*cc4ad7daSAndroid Build Coastguard Worker 	char buf[PATH_MAX];
274*cc4ad7daSAndroid Build Coastguard Worker 
275*cc4ad7daSAndroid Build Coastguard Worker 	struct kmod_builtin_iter *iter = kmod_builtin_iter_new(ctx);
276*cc4ad7daSAndroid Build Coastguard Worker 
277*cc4ad7daSAndroid Build Coastguard Worker 	if (!iter)
278*cc4ad7daSAndroid Build Coastguard Worker 		return -errno;
279*cc4ad7daSAndroid Build Coastguard Worker 
280*cc4ad7daSAndroid Build Coastguard Worker 	while (!name && kmod_builtin_iter_next(iter)) {
281*cc4ad7daSAndroid Build Coastguard Worker 		if (!kmod_builtin_iter_get_modname(iter, buf)) {
282*cc4ad7daSAndroid Build Coastguard Worker 			count = -errno;
283*cc4ad7daSAndroid Build Coastguard Worker 			goto fail;
284*cc4ad7daSAndroid Build Coastguard Worker 		}
285*cc4ad7daSAndroid Build Coastguard Worker 
286*cc4ad7daSAndroid Build Coastguard Worker 		if (strcmp(modname, buf))
287*cc4ad7daSAndroid Build Coastguard Worker 			continue;
288*cc4ad7daSAndroid Build Coastguard Worker 
289*cc4ad7daSAndroid Build Coastguard Worker 		name = buf;
290*cc4ad7daSAndroid Build Coastguard Worker 	}
291*cc4ad7daSAndroid Build Coastguard Worker 
292*cc4ad7daSAndroid Build Coastguard Worker 	if (!name) {
293*cc4ad7daSAndroid Build Coastguard Worker 		count = -ENOSYS;
294*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
295*cc4ad7daSAndroid Build Coastguard Worker 	}
296*cc4ad7daSAndroid Build Coastguard Worker 
297*cc4ad7daSAndroid Build Coastguard Worker 	modlen = strlen(modname) + 1;
298*cc4ad7daSAndroid Build Coastguard Worker 	count = iter->nstrings;
299*cc4ad7daSAndroid Build Coastguard Worker 	size = iter->next - iter->pos - (modlen * count);
300*cc4ad7daSAndroid Build Coastguard Worker 
301*cc4ad7daSAndroid Build Coastguard Worker 	*modinfo = malloc(size + sizeof(char *) * (count + 1));
302*cc4ad7daSAndroid Build Coastguard Worker 	if (!*modinfo) {
303*cc4ad7daSAndroid Build Coastguard Worker 		count = -errno;
304*cc4ad7daSAndroid Build Coastguard Worker 		goto fail;
305*cc4ad7daSAndroid Build Coastguard Worker 	}
306*cc4ad7daSAndroid Build Coastguard Worker 
307*cc4ad7daSAndroid Build Coastguard Worker 	s = (char *)(*modinfo + count + 1);
308*cc4ad7daSAndroid Build Coastguard Worker 	i = 0;
309*cc4ad7daSAndroid Build Coastguard Worker 
310*cc4ad7daSAndroid Build Coastguard Worker 	n = 0;
311*cc4ad7daSAndroid Build Coastguard Worker 	offset = pos = iter->pos;
312*cc4ad7daSAndroid Build Coastguard Worker 
313*cc4ad7daSAndroid Build Coastguard Worker 	while (offset < iter->next) {
314*cc4ad7daSAndroid Build Coastguard Worker 		offset = get_string(iter, pos, &line, &linesz);
315*cc4ad7daSAndroid Build Coastguard Worker 		if (offset <= 0) {
316*cc4ad7daSAndroid Build Coastguard Worker 			count = (offset) ? -errno : -EINVAL;
317*cc4ad7daSAndroid Build Coastguard Worker 			free(*modinfo);
318*cc4ad7daSAndroid Build Coastguard Worker 			goto fail;
319*cc4ad7daSAndroid Build Coastguard Worker 		}
320*cc4ad7daSAndroid Build Coastguard Worker 
321*cc4ad7daSAndroid Build Coastguard Worker 		strcpy(s + i, line + modlen);
322*cc4ad7daSAndroid Build Coastguard Worker 		(*modinfo)[n++] = s + i;
323*cc4ad7daSAndroid Build Coastguard Worker 		i += linesz - modlen;
324*cc4ad7daSAndroid Build Coastguard Worker 
325*cc4ad7daSAndroid Build Coastguard Worker 		pos = offset;
326*cc4ad7daSAndroid Build Coastguard Worker 	}
327*cc4ad7daSAndroid Build Coastguard Worker fail:
328*cc4ad7daSAndroid Build Coastguard Worker 	kmod_builtin_iter_free(iter);
329*cc4ad7daSAndroid Build Coastguard Worker 	return count;
330*cc4ad7daSAndroid Build Coastguard Worker }
331