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
41const char * program_name = "get_fstab";
42char * 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;
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		return retval;
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		return retval;
113
114	ret_file->buf = buf;
115	ret_file->size = (int) got;
116
117errout:
118	ext2fs_file_close(e2_file);
119	return retval;
120}
121
122static char *get_line(struct mem_file *file)
123{
124	char	*cp, *ret;
125	int	s = 0;
126
127	cp = file->buf + file->ptr;
128	while (*cp && *cp != '\n') {
129		cp++;
130		s++;
131	}
132	ret = malloc(s+1);
133	if (!ret)
134		return 0;
135	ret[s]=0;
136	memcpy(ret, file->buf + file->ptr, s);
137	while (*cp && (*cp == '\n' || *cp == '\r')) {
138		cp++;
139		s++;
140	}
141	file->ptr += s;
142	return ret;
143}
144
145static int mem_file_eof(struct mem_file *file)
146{
147	return (file->ptr >= file->size);
148}
149
150/*
151 * fstab parsing code
152 */
153static char *string_copy(const char *s)
154{
155	char	*ret;
156
157	if (!s)
158		return 0;
159	ret = malloc(strlen(s)+1);
160	if (ret)
161		strcpy(ret, s);
162	return ret;
163}
164
165static char *skip_over_blank(char *cp)
166{
167	while (*cp && isspace(*cp))
168		cp++;
169	return cp;
170}
171
172static char *skip_over_word(char *cp)
173{
174	while (*cp && !isspace(*cp))
175		cp++;
176	return cp;
177}
178
179static char *parse_word(char **buf)
180{
181	char *word, *next;
182
183	word = *buf;
184	if (*word == 0)
185		return 0;
186
187	word = skip_over_blank(word);
188	next = skip_over_word(word);
189	if (*next)
190		*next++ = 0;
191	*buf = next;
192	return word;
193}
194
195static void parse_escape(char *word)
196{
197	char	*p, *q;
198	int	ac, i;
199
200	if (!word)
201		return;
202
203	for (p = word, q = word; *p; p++, q++) {
204		*q = *p;
205		if (*p != '\\')
206			continue;
207		if (*++p == 0)
208			break;
209		if (*p == 't') {
210			*q = '\t';
211			continue;
212		}
213		if (*p == 'n') {
214			*q = '\n';
215			continue;
216		}
217		if (!isdigit(*p)) {
218			*q = *p;
219			continue;
220		}
221		ac = 0;
222		for (i = 0; i < 3; i++, p++) {
223			if (!isdigit(*p))
224				break;
225			ac = (ac * 8) + (*p - '0');
226		}
227		*q = ac;
228		p--;
229	}
230	*q = 0;
231}
232
233static int parse_fstab_line(char *line, struct fs_info *fs)
234{
235	char	*dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
236
237	if ((cp = strchr(line, '#')))
238		*cp = 0;	/* Ignore everything after the comment char */
239	cp = line;
240
241	device = parse_word(&cp);
242	mntpnt = parse_word(&cp);
243	type = parse_word(&cp);
244	opts = parse_word(&cp);
245	freq = parse_word(&cp);
246	passno = parse_word(&cp);
247
248	if (!device)
249		return -1;	/* Allow blank lines */
250
251	if (!mntpnt || !type)
252		return -1;
253
254	parse_escape(device);
255	parse_escape(mntpnt);
256	parse_escape(type);
257	parse_escape(opts);
258	parse_escape(freq);
259	parse_escape(passno);
260
261	dev = blkid_get_devname(cache, device, NULL);
262	if (dev)
263		device = dev;
264
265	if (strchr(type, ','))
266		type = 0;
267
268	fs->device = string_copy(device);
269	fs->mountpt = string_copy(mntpnt);
270	fs->type = string_copy(type);
271	fs->opts = string_copy(opts ? opts : "");
272	fs->freq = freq ? atoi(freq) : -1;
273	fs->passno = passno ? atoi(passno) : -1;
274	fs->flags = 0;
275	fs->next = NULL;
276
277	free(dev);
278
279	return 0;
280}
281
282static void free_fstab_line(struct fs_info *fs)
283{
284	if (fs->device)
285		fs->device = 0;
286	if (fs->mountpt)
287		fs->mountpt = 0;
288	if (fs->type)
289		fs->type = 0;
290	if (fs->opts)
291		fs->opts = 0;
292	memset(fs, 0, sizeof(struct fs_info));
293}
294
295
296static void PRS(int argc, char **argv)
297{
298	int c;
299
300#ifdef ENABLE_NLS
301	setlocale(LC_MESSAGES, "");
302	setlocale(LC_CTYPE, "");
303	bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
304	textdomain(NLS_CAT_NAME);
305#endif
306
307	while ((c = getopt(argc, argv, "rv")) != EOF) {
308		switch (c) {
309		case 'r':
310			root_type++;
311			break;
312
313		case 'v':
314			printf("%s %s (%s)\n", program_name,
315			       E2FSPROGS_VERSION, E2FSPROGS_DATE);
316			break;
317		default:
318			usage();
319		}
320	}
321	if (optind < argc - 1 || optind == argc)
322		usage();
323	device_name = blkid_get_devname(NULL, argv[optind], NULL);
324	if (!device_name) {
325		com_err("tune2fs", 0, _("Unable to resolve '%s'"),
326			argv[optind]);
327		exit(1);
328	}
329}
330
331static void get_root_type(ext2_filsys fs)
332{
333	errcode_t retval;
334	struct mem_file file;
335	char 		*buf;
336	struct fs_info fs_info;
337	int		ret;
338
339	retval = get_file(fs, "/etc/fstab", &file);
340
341	while (!mem_file_eof(&file)) {
342		buf = get_line(&file);
343		if (!buf)
344			continue;
345
346		ret = parse_fstab_line(buf, &fs_info);
347		if (ret < 0)
348			goto next_line;
349
350		if (!strcmp(fs_info.mountpt, "/"))
351			printf("%s\n", fs_info.type);
352
353		free_fstab_line(&fs_info);
354
355	next_line:
356		free(buf);
357	}
358}
359
360
361int main (int argc, char ** argv)
362{
363	errcode_t retval;
364	ext2_filsys fs;
365	io_manager io_ptr;
366
367	add_error_table(&et_ext2_error_table);
368
369	blkid_get_cache(&cache, NULL);
370	PRS(argc, argv);
371
372#ifdef CONFIG_TESTIO_DEBUG
373	if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) {
374		io_ptr = test_io_manager;
375		test_io_backing_manager = unix_io_manager;
376	} else
377#endif
378		io_ptr = unix_io_manager;
379	retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs);
380        if (retval)
381		exit(1);
382
383	if (root_type)
384		get_root_type(fs);
385
386	remove_error_table(&et_ext2_error_table);
387	return (ext2fs_close (fs) ? 1 : 0);
388}
389