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 const char * program_name = "get_fstab";
     42 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;
     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 
    117 errout:
    118 	ext2fs_file_close(e2_file);
    119 	return retval;
    120 }
    121 
    122 static 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 
    145 static int mem_file_eof(struct mem_file *file)
    146 {
    147 	return (file->ptr >= file->size);
    148 }
    149 
    150 /*
    151  * fstab parsing code
    152  */
    153 static 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 
    165 static char *skip_over_blank(char *cp)
    166 {
    167 	while (*cp && isspace(*cp))
    168 		cp++;
    169 	return cp;
    170 }
    171 
    172 static char *skip_over_word(char *cp)
    173 {
    174 	while (*cp && !isspace(*cp))
    175 		cp++;
    176 	return cp;
    177 }
    178 
    179 static 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 
    195 static 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 
    233 static 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 
    282 static 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 
    296 static 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 
    331 static 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 
    361 int 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