e2initrd_helper.c revision e0ed7404719a9ddd2ba427a80db5365c8bad18c0
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
30extern int optind;
31extern 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
41static const char * program_name = "e2initrd_helper";
42static char * device_name;
43static int open_flag;
44static int root_type;
45static blkid_cache cache = NULL;
46
47struct mem_file {
48	char	*buf;
49	int	size;
50	int	ptr;
51};
52
53struct 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
64static void usage(void)
65{
66	fprintf(stderr,
67		_("Usage: %s -r device\n"), program_name);
68	exit (1);
69}
70
71static 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
118errout:
119	free(buf);
120	if (e2_file)
121		ext2fs_file_close(e2_file);
122	return retval;
123}
124
125static 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
148static int mem_file_eof(struct mem_file *file)
149{
150	return (file->ptr >= file->size);
151}
152
153/*
154 * fstab parsing code
155 */
156static 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
168static char *skip_over_blank(char *cp)
169{
170	while (*cp && isspace(*cp))
171		cp++;
172	return cp;
173}
174
175static char *skip_over_word(char *cp)
176{
177	while (*cp && !isspace(*cp))
178		cp++;
179	return cp;
180}
181
182static 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
198static 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
236static 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
285static 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
299static 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
335static 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
369int 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