Home | History | Annotate | Download | only in misc
      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 
     64 static void usage(void)
     65 {
     66 	fprintf(stderr,
     67 		_("Usage: %s -r device\n"), program_name);
     68 	exit (1);
     69 }
     70 
     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 
    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 
    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  */
    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 
    168 static char *skip_over_blank(char *cp)
    169 {
    170 	while (*cp && isspace(*cp))
    171 		cp++;
    172 	return cp;
    173 }
    174 
    175 static char *skip_over_word(char *cp)
    176 {
    177 	while (*cp && !isspace(*cp))
    178 		cp++;
    179 	return cp;
    180 }
    181 
    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 
    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 
    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 
    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 
    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 
    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 
    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