xref: /aosp_15_r20/external/e2fsprogs/misc/e2initrd_helper.c (revision 6a54128f25917bfc36a8a6e9d722c04a0b4641b6)
1 /*
2  * e2initrd_helper.c - Get the filesystem table
3  *
4  * Copyright 2004 by Theodore Ts'o.
5  *
6  * %Begin-Header%
7  * This file may be redistributed under the terms of the GNU Public
8  * License.
9  * %End-Header%
10  */
11 
12 #include "config.h"
13 #include <stdio.h>
14 #include <unistd.h>
15 #ifdef HAVE_STDLIB_H
16 #include <stdlib.h>
17 #endif
18 #include <ctype.h>
19 #include <string.h>
20 #include <time.h>
21 #ifdef HAVE_ERRNO_H
22 #include <errno.h>
23 #endif
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <utime.h>
28 #ifdef HAVE_GETOPT_H
29 #include <getopt.h>
30 #else
31 extern int optind;
32 extern char *optarg;
33 #endif
34 
35 #include "ext2fs/ext2_fs.h"
36 #include "ext2fs/ext2fs.h"
37 #include "blkid/blkid.h"
38 #include "support/nls-enable.h"
39 #include "support/devname.h"
40 
41 #include "../version.h"
42 
43 static const char * program_name = "e2initrd_helper";
44 static char * device_name;
45 static int open_flag;
46 static int root_type;
47 static blkid_cache cache = NULL;
48 
49 struct mem_file {
50 	char	*buf;
51 	int	size;
52 	int	ptr;
53 };
54 
55 struct fs_info {
56 	char  *device;
57 	char  *mountpt;
58 	char  *type;
59 	char  *opts;
60 	int   freq;
61 	int   passno;
62 	int   flags;
63 	struct fs_info *next;
64 };
65 
usage(void)66 static void usage(void)
67 {
68 	fprintf(stderr,
69 		_("Usage: %s -r device\n"), program_name);
70 	exit (1);
71 }
72 
get_file(ext2_filsys fs,const char * filename,struct mem_file * ret_file)73 static errcode_t get_file(ext2_filsys fs, const char * filename,
74 		   struct mem_file *ret_file)
75 {
76 	errcode_t	retval;
77 	char 		*buf;
78 	ext2_file_t	e2_file = NULL;
79 	unsigned int	got;
80 	struct ext2_inode inode;
81 	ext2_ino_t	ino;
82 
83 	ret_file->buf = 0;
84 	ret_file->size = 0;
85 	ret_file->ptr = 0;
86 
87 	retval = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
88 			      filename, &ino);
89 	if (retval)
90 		return retval;
91 
92 	retval = ext2fs_read_inode(fs, ino, &inode);
93 	if (retval)
94 		return retval;
95 
96 	if (inode.i_size_high || (inode.i_size > 65536))
97 		return EFBIG;
98 
99 	buf = malloc(inode.i_size + 1);
100 	if (!buf)
101 		return ENOMEM;
102 	memset(buf, 0, inode.i_size+1);
103 
104 	retval = ext2fs_file_open(fs, ino, 0, &e2_file);
105 	if (retval)
106 		goto errout;
107 
108 	retval = ext2fs_file_read(e2_file, buf, inode.i_size, &got);
109 	if (retval)
110 		goto errout;
111 
112 	retval = ext2fs_file_close(e2_file);
113 	if (retval)
114 		goto errout;
115 
116 	ret_file->buf = buf;
117 	ret_file->size = (int) got;
118 	return 0;
119 
120 errout:
121 	free(buf);
122 	if (e2_file)
123 		ext2fs_file_close(e2_file);
124 	return retval;
125 }
126 
get_line(struct mem_file * file)127 static char *get_line(struct mem_file *file)
128 {
129 	char	*cp, *ret;
130 	int	s = 0;
131 
132 	cp = file->buf + file->ptr;
133 	while (*cp && *cp != '\n') {
134 		cp++;
135 		s++;
136 	}
137 	ret = malloc(s+1);
138 	if (!ret)
139 		return 0;
140 	ret[s]=0;
141 	memcpy(ret, file->buf + file->ptr, s);
142 	while (*cp && (*cp == '\n' || *cp == '\r')) {
143 		cp++;
144 		s++;
145 	}
146 	file->ptr += s;
147 	return ret;
148 }
149 
mem_file_eof(struct mem_file * file)150 static int mem_file_eof(struct mem_file *file)
151 {
152 	return (file->ptr >= file->size);
153 }
154 
155 /*
156  * fstab parsing code
157  */
string_copy(const char * s)158 static char *string_copy(const char *s)
159 {
160 	char	*ret;
161 
162 	if (!s)
163 		return 0;
164 	ret = malloc(strlen(s)+1);
165 	if (ret)
166 		strcpy(ret, s);
167 	return ret;
168 }
169 
skip_over_blank(char * cp)170 static char *skip_over_blank(char *cp)
171 {
172 	while (*cp && isspace(*cp))
173 		cp++;
174 	return cp;
175 }
176 
skip_over_word(char * cp)177 static char *skip_over_word(char *cp)
178 {
179 	while (*cp && !isspace(*cp))
180 		cp++;
181 	return cp;
182 }
183 
parse_word(char ** buf)184 static char *parse_word(char **buf)
185 {
186 	char *word, *next;
187 
188 	word = *buf;
189 	if (*word == 0)
190 		return 0;
191 
192 	word = skip_over_blank(word);
193 	next = skip_over_word(word);
194 	if (*next)
195 		*next++ = 0;
196 	*buf = next;
197 	return word;
198 }
199 
parse_escape(char * word)200 static void parse_escape(char *word)
201 {
202 	char	*p, *q;
203 	int	ac, i;
204 
205 	if (!word)
206 		return;
207 
208 	for (p = word, q = word; *p; p++, q++) {
209 		*q = *p;
210 		if (*p != '\\')
211 			continue;
212 		if (*++p == 0)
213 			break;
214 		if (*p == 't') {
215 			*q = '\t';
216 			continue;
217 		}
218 		if (*p == 'n') {
219 			*q = '\n';
220 			continue;
221 		}
222 		if (!isdigit(*p)) {
223 			*q = *p;
224 			continue;
225 		}
226 		ac = 0;
227 		for (i = 0; i < 3; i++, p++) {
228 			if (!isdigit(*p))
229 				break;
230 			ac = (ac * 8) + (*p - '0');
231 		}
232 		*q = ac;
233 		p--;
234 	}
235 	*q = 0;
236 }
237 
parse_fstab_line(char * line,struct fs_info * fs)238 static int parse_fstab_line(char *line, struct fs_info *fs)
239 {
240 	char	*dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
241 
242 	if ((cp = strchr(line, '#')))
243 		*cp = 0;	/* Ignore everything after the comment char */
244 	cp = line;
245 
246 	device = parse_word(&cp);
247 	mntpnt = parse_word(&cp);
248 	type = parse_word(&cp);
249 	opts = parse_word(&cp);
250 	freq = parse_word(&cp);
251 	passno = parse_word(&cp);
252 
253 	if (!device)
254 		return -1;	/* Allow blank lines */
255 
256 	if (!mntpnt || !type)
257 		return -1;
258 
259 	parse_escape(device);
260 	parse_escape(mntpnt);
261 	parse_escape(type);
262 	parse_escape(opts);
263 	parse_escape(freq);
264 	parse_escape(passno);
265 
266 	dev = get_devname(cache, device, NULL);
267 	if (dev)
268 		device = dev;
269 
270 	if (strchr(type, ','))
271 		type = 0;
272 
273 	fs->device = string_copy(device);
274 	fs->mountpt = string_copy(mntpnt);
275 	fs->type = string_copy(type);
276 	fs->opts = string_copy(opts ? opts : "");
277 	fs->freq = freq ? atoi(freq) : -1;
278 	fs->passno = passno ? atoi(passno) : -1;
279 	fs->flags = 0;
280 	fs->next = NULL;
281 
282 	free(dev);
283 
284 	return 0;
285 }
286 
free_fstab_line(struct fs_info * fs)287 static void free_fstab_line(struct fs_info *fs)
288 {
289 	if (fs->device)
290 		fs->device = 0;
291 	if (fs->mountpt)
292 		fs->mountpt = 0;
293 	if (fs->type)
294 		fs->type = 0;
295 	if (fs->opts)
296 		fs->opts = 0;
297 	memset(fs, 0, sizeof(struct fs_info));
298 }
299 
300 
PRS(int argc,char ** argv)301 static void PRS(int argc, char **argv)
302 {
303 	int c;
304 
305 #ifdef ENABLE_NLS
306 	setlocale(LC_MESSAGES, "");
307 	setlocale(LC_CTYPE, "");
308 	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
309 	textdomain(NLS_CAT_NAME);
310 	set_com_err_gettext(gettext);
311 #endif
312 
313 	while ((c = getopt(argc, argv, "rv")) != EOF) {
314 		switch (c) {
315 		case 'r':
316 			root_type++;
317 			break;
318 
319 		case 'v':
320 			printf("%s %s (%s)\n", program_name,
321 			       E2FSPROGS_VERSION, E2FSPROGS_DATE);
322 			break;
323 		default:
324 			usage();
325 		}
326 	}
327 	if (optind < argc - 1 || optind == argc)
328 		usage();
329 	device_name = get_devname(NULL, argv[optind], NULL);
330 	if (!device_name) {
331 		com_err(program_name, 0, _("Unable to resolve '%s'"),
332 			argv[optind]);
333 		exit(1);
334 	}
335 }
336 
get_root_type(ext2_filsys fs)337 static void get_root_type(ext2_filsys fs)
338 {
339 	errcode_t retval;
340 	struct mem_file file;
341 	char 		*buf;
342 	struct fs_info fs_info;
343 	int		ret;
344 
345 	retval = get_file(fs, "/etc/fstab", &file);
346 	if (retval) {
347 		com_err(program_name, retval, "couldn't open /etc/fstab");
348 		exit(1);
349 	}
350 
351 	while (!mem_file_eof(&file)) {
352 		buf = get_line(&file);
353 		if (!buf)
354 			continue;
355 
356 		ret = parse_fstab_line(buf, &fs_info);
357 		if (ret < 0)
358 			goto next_line;
359 
360 		if (!strcmp(fs_info.mountpt, "/"))
361 			printf("%s\n", fs_info.type);
362 
363 		free_fstab_line(&fs_info);
364 
365 	next_line:
366 		free(buf);
367 	}
368 }
369 
370 
main(int argc,char ** argv)371 int main (int argc, char ** argv)
372 {
373 	errcode_t retval;
374 	ext2_filsys fs;
375 	io_manager io_ptr;
376 
377 	add_error_table(&et_ext2_error_table);
378 
379 	blkid_get_cache(&cache, NULL);
380 	PRS(argc, argv);
381 
382 #ifdef CONFIG_TESTIO_DEBUG
383 	if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
384 		io_ptr = test_io_manager;
385 		test_io_backing_manager = unix_io_manager;
386 	} else
387 #endif
388 		io_ptr = unix_io_manager;
389 	retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs);
390         if (retval)
391 		exit(1);
392 
393 	if (root_type)
394 		get_root_type(fs);
395 
396 	remove_error_table(&et_ext2_error_table);
397 	return (ext2fs_close (fs) ? 1 : 0);
398 }
399