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