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 31extern int optind; 32extern 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 42static const char * program_name = "e2initrd_helper"; 43static char * device_name; 44static int open_flag; 45static int root_type; 46static blkid_cache cache = NULL; 47 48struct mem_file { 49 char *buf; 50 int size; 51 int ptr; 52}; 53 54struct 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 65static void usage(void) 66{ 67 fprintf(stderr, 68 _("Usage: %s -r device\n"), program_name); 69 exit (1); 70} 71 72static 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 119errout: 120 free(buf); 121 if (e2_file) 122 ext2fs_file_close(e2_file); 123 return retval; 124} 125 126static 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 149static int mem_file_eof(struct mem_file *file) 150{ 151 return (file->ptr >= file->size); 152} 153 154/* 155 * fstab parsing code 156 */ 157static 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 169static char *skip_over_blank(char *cp) 170{ 171 while (*cp && isspace(*cp)) 172 cp++; 173 return cp; 174} 175 176static char *skip_over_word(char *cp) 177{ 178 while (*cp && !isspace(*cp)) 179 cp++; 180 return cp; 181} 182 183static 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 199static 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 237static 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 286static 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 300static 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 336static 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 370int 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