e2initrd_helper.c revision efc6f628e15de95bcd13e4f0ee223cb42115d520
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#include <stdlib.h>
15#include <ctype.h>
16#include <string.h>
17#include <time.h>
18#ifdef HAVE_ERRNO_H
19#include <errno.h>
20#endif
21#include <sys/types.h>
22#include <sys/stat.h>
23#include <fcntl.h>
24#include <utime.h>
25#ifdef HAVE_GETOPT_H
26#include <getopt.h>
27#else
28extern int optind;
29extern char *optarg;
30#endif
31
32#include "ext2fs/ext2_fs.h"
33#include "ext2fs/ext2fs.h"
34#include "e2p/e2p.h"
35#include "blkid/blkid.h"
36
37#include "../version.h"
38#include "nls-enable.h"
39
40const char * program_name = "get_fstab";
41char * device_name;
42static int open_flag;
43static int root_type;
44static blkid_cache cache = NULL;
45
46struct mem_file {
47	char	*buf;
48	int	size;
49	int	ptr;
50};
51
52struct fs_info {
53	char  *device;
54	char  *mountpt;
55	char  *type;
56	char  *opts;
57	int   freq;
58	int   passno;
59	int   flags;
60	struct fs_info *next;
61};
62
63static void usage(void)
64{
65	fprintf(stderr,
66		_("Usage: %s -r device\n"), program_name);
67	exit (1);
68}
69
70static errcode_t get_file(ext2_filsys fs, const char * filename,
71		   struct mem_file *ret_file)
72{
73	errcode_t	retval;
74	char 		*buf;
75	ext2_file_t	e2_file;
76	unsigned int	got;
77	struct ext2_inode inode;
78	ext2_ino_t	ino;
79
80	ret_file->buf = 0;
81	ret_file->size = 0;
82	ret_file->ptr = 0;
83
84	retval = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO,
85			      filename, &ino);
86	if (retval)
87		return retval;
88
89	retval = ext2fs_read_inode(fs, ino, &inode);
90	if (retval)
91		return retval;
92
93	if (inode.i_size_high || (inode.i_size > 65536))
94		return EFBIG;
95
96	buf = malloc(inode.i_size + 1);
97	if (!buf)
98		return ENOMEM;
99	memset(buf, 0, inode.i_size+1);
100
101	retval = ext2fs_file_open(fs, ino, 0, &e2_file);
102	if (retval)
103		return retval;
104
105	retval = ext2fs_file_read(e2_file, buf, inode.i_size, &got);
106	if (retval)
107		goto errout;
108
109	retval = ext2fs_file_close(e2_file);
110	if (retval)
111		return retval;
112
113	ret_file->buf = buf;
114	ret_file->size = (int) got;
115
116errout:
117	ext2fs_file_close(e2_file);
118	return retval;
119}
120
121static char *get_line(struct mem_file *file)
122{
123	char	*cp, *ret;
124	int	s = 0;
125
126	cp = file->buf + file->ptr;
127	while (*cp && *cp != '\n') {
128		cp++;
129		s++;
130	}
131	ret = malloc(s+1);
132	if (!ret)
133		return 0;
134	ret[s]=0;
135	memcpy(ret, file->buf + file->ptr, s);
136	while (*cp && (*cp == '\n' || *cp == '\r')) {
137		cp++;
138		s++;
139	}
140	file->ptr += s;
141	return ret;
142}
143
144static int mem_file_eof(struct mem_file *file)
145{
146	return (file->ptr >= file->size);
147}
148
149/*
150 * fstab parsing code
151 */
152static char *string_copy(const char *s)
153{
154	char	*ret;
155
156	if (!s)
157		return 0;
158	ret = malloc(strlen(s)+1);
159	if (ret)
160		strcpy(ret, s);
161	return ret;
162}
163
164static char *skip_over_blank(char *cp)
165{
166	while (*cp && isspace(*cp))
167		cp++;
168	return cp;
169}
170
171static char *skip_over_word(char *cp)
172{
173	while (*cp && !isspace(*cp))
174		cp++;
175	return cp;
176}
177
178static char *parse_word(char **buf)
179{
180	char *word, *next;
181
182	word = *buf;
183	if (*word == 0)
184		return 0;
185
186	word = skip_over_blank(word);
187	next = skip_over_word(word);
188	if (*next)
189		*next++ = 0;
190	*buf = next;
191	return word;
192}
193
194static void parse_escape(char *word)
195{
196	char	*p, *q;
197	int	ac, i;
198
199	if (!word)
200		return;
201
202	for (p = word, q = word; *p; p++, q++) {
203		*q = *p;
204		if (*p != '\\')
205			continue;
206		if (*++p == 0)
207			break;
208		if (*p == 't') {
209			*q = '\t';
210			continue;
211		}
212		if (*p == 'n') {
213			*q = '\n';
214			continue;
215		}
216		if (!isdigit(*p)) {
217			*q = *p;
218			continue;
219		}
220		ac = 0;
221		for (i = 0; i < 3; i++, p++) {
222			if (!isdigit(*p))
223				break;
224			ac = (ac * 8) + (*p - '0');
225		}
226		*q = ac;
227		p--;
228	}
229	*q = 0;
230}
231
232static int parse_fstab_line(char *line, struct fs_info *fs)
233{
234	char	*dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp;
235
236	if ((cp = strchr(line, '#')))
237		*cp = 0;	/* Ignore everything after the comment char */
238	cp = line;
239
240	device = parse_word(&cp);
241	mntpnt = parse_word(&cp);
242	type = parse_word(&cp);
243	opts = parse_word(&cp);
244	freq = parse_word(&cp);
245	passno = parse_word(&cp);
246
247	if (!device)
248		return -1;	/* Allow blank lines */
249
250	if (!mntpnt || !type)
251		return -1;
252
253	parse_escape(device);
254	parse_escape(mntpnt);
255	parse_escape(type);
256	parse_escape(opts);
257	parse_escape(freq);
258	parse_escape(passno);
259
260	dev = blkid_get_devname(cache, device, NULL);
261	if (dev)
262		device = dev;
263
264	if (strchr(type, ','))
265		type = 0;
266
267	fs->device = string_copy(device);
268	fs->mountpt = string_copy(mntpnt);
269	fs->type = string_copy(type);
270	fs->opts = string_copy(opts ? opts : "");
271	fs->freq = freq ? atoi(freq) : -1;
272	fs->passno = passno ? atoi(passno) : -1;
273	fs->flags = 0;
274	fs->next = NULL;
275
276	if (dev)
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	io_ptr = test_io_manager;
374	test_io_backing_manager = unix_io_manager;
375#else
376	io_ptr = unix_io_manager;
377#endif
378	retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs);
379        if (retval)
380		exit(1);
381
382	if (root_type)
383		get_root_type(fs);
384
385	remove_error_table(&et_ext2_error_table);
386	return (ext2fs_close (fs) ? 1 : 0);
387}
388