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 #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
     28 extern int optind;
     29 extern 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 
     40 const char * program_name = "get_fstab";
     41 char * device_name;
     42 static int open_flag;
     43 static int root_type;
     44 static blkid_cache cache = NULL;
     45 
     46 struct mem_file {
     47 	char	*buf;
     48 	int	size;
     49 	int	ptr;
     50 };
     51 
     52 struct 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 
     63 static void usage(void)
     64 {
     65 	fprintf(stderr,
     66 		_("Usage: %s -r device\n"), program_name);
     67 	exit (1);
     68 }
     69 
     70 static 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 
    116 errout:
    117 	ext2fs_file_close(e2_file);
    118 	return retval;
    119 }
    120 
    121 static 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 
    144 static int mem_file_eof(struct mem_file *file)
    145 {
    146 	return (file->ptr >= file->size);
    147 }
    148 
    149 /*
    150  * fstab parsing code
    151  */
    152 static 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 
    164 static char *skip_over_blank(char *cp)
    165 {
    166 	while (*cp && isspace(*cp))
    167 		cp++;
    168 	return cp;
    169 }
    170 
    171 static char *skip_over_word(char *cp)
    172 {
    173 	while (*cp && !isspace(*cp))
    174 		cp++;
    175 	return cp;
    176 }
    177 
    178 static 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 
    194 static 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 
    232 static 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 
    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 	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