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