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