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 static const char * program_name = "e2initrd_helper"; 42 static 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 = NULL; 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 goto errout; 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 goto errout; 113 114 ret_file->buf = buf; 115 ret_file->size = (int) got; 116 return 0; 117 118 errout: 119 free(buf); 120 if (e2_file) 121 ext2fs_file_close(e2_file); 122 return retval; 123 } 124 125 static char *get_line(struct mem_file *file) 126 { 127 char *cp, *ret; 128 int s = 0; 129 130 cp = file->buf + file->ptr; 131 while (*cp && *cp != '\n') { 132 cp++; 133 s++; 134 } 135 ret = malloc(s+1); 136 if (!ret) 137 return 0; 138 ret[s]=0; 139 memcpy(ret, file->buf + file->ptr, s); 140 while (*cp && (*cp == '\n' || *cp == '\r')) { 141 cp++; 142 s++; 143 } 144 file->ptr += s; 145 return ret; 146 } 147 148 static int mem_file_eof(struct mem_file *file) 149 { 150 return (file->ptr >= file->size); 151 } 152 153 /* 154 * fstab parsing code 155 */ 156 static char *string_copy(const char *s) 157 { 158 char *ret; 159 160 if (!s) 161 return 0; 162 ret = malloc(strlen(s)+1); 163 if (ret) 164 strcpy(ret, s); 165 return ret; 166 } 167 168 static char *skip_over_blank(char *cp) 169 { 170 while (*cp && isspace(*cp)) 171 cp++; 172 return cp; 173 } 174 175 static char *skip_over_word(char *cp) 176 { 177 while (*cp && !isspace(*cp)) 178 cp++; 179 return cp; 180 } 181 182 static char *parse_word(char **buf) 183 { 184 char *word, *next; 185 186 word = *buf; 187 if (*word == 0) 188 return 0; 189 190 word = skip_over_blank(word); 191 next = skip_over_word(word); 192 if (*next) 193 *next++ = 0; 194 *buf = next; 195 return word; 196 } 197 198 static void parse_escape(char *word) 199 { 200 char *p, *q; 201 int ac, i; 202 203 if (!word) 204 return; 205 206 for (p = word, q = word; *p; p++, q++) { 207 *q = *p; 208 if (*p != '\\') 209 continue; 210 if (*++p == 0) 211 break; 212 if (*p == 't') { 213 *q = '\t'; 214 continue; 215 } 216 if (*p == 'n') { 217 *q = '\n'; 218 continue; 219 } 220 if (!isdigit(*p)) { 221 *q = *p; 222 continue; 223 } 224 ac = 0; 225 for (i = 0; i < 3; i++, p++) { 226 if (!isdigit(*p)) 227 break; 228 ac = (ac * 8) + (*p - '0'); 229 } 230 *q = ac; 231 p--; 232 } 233 *q = 0; 234 } 235 236 static int parse_fstab_line(char *line, struct fs_info *fs) 237 { 238 char *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp; 239 240 if ((cp = strchr(line, '#'))) 241 *cp = 0; /* Ignore everything after the comment char */ 242 cp = line; 243 244 device = parse_word(&cp); 245 mntpnt = parse_word(&cp); 246 type = parse_word(&cp); 247 opts = parse_word(&cp); 248 freq = parse_word(&cp); 249 passno = parse_word(&cp); 250 251 if (!device) 252 return -1; /* Allow blank lines */ 253 254 if (!mntpnt || !type) 255 return -1; 256 257 parse_escape(device); 258 parse_escape(mntpnt); 259 parse_escape(type); 260 parse_escape(opts); 261 parse_escape(freq); 262 parse_escape(passno); 263 264 dev = blkid_get_devname(cache, device, NULL); 265 if (dev) 266 device = dev; 267 268 if (strchr(type, ',')) 269 type = 0; 270 271 fs->device = string_copy(device); 272 fs->mountpt = string_copy(mntpnt); 273 fs->type = string_copy(type); 274 fs->opts = string_copy(opts ? opts : ""); 275 fs->freq = freq ? atoi(freq) : -1; 276 fs->passno = passno ? atoi(passno) : -1; 277 fs->flags = 0; 278 fs->next = NULL; 279 280 free(dev); 281 282 return 0; 283 } 284 285 static void free_fstab_line(struct fs_info *fs) 286 { 287 if (fs->device) 288 fs->device = 0; 289 if (fs->mountpt) 290 fs->mountpt = 0; 291 if (fs->type) 292 fs->type = 0; 293 if (fs->opts) 294 fs->opts = 0; 295 memset(fs, 0, sizeof(struct fs_info)); 296 } 297 298 299 static void PRS(int argc, char **argv) 300 { 301 int c; 302 303 #ifdef ENABLE_NLS 304 setlocale(LC_MESSAGES, ""); 305 setlocale(LC_CTYPE, ""); 306 bindtextdomain(NLS_CAT_NAME, LOCALEDIR); 307 textdomain(NLS_CAT_NAME); 308 set_com_err_gettext(gettext); 309 #endif 310 311 while ((c = getopt(argc, argv, "rv")) != EOF) { 312 switch (c) { 313 case 'r': 314 root_type++; 315 break; 316 317 case 'v': 318 printf("%s %s (%s)\n", program_name, 319 E2FSPROGS_VERSION, E2FSPROGS_DATE); 320 break; 321 default: 322 usage(); 323 } 324 } 325 if (optind < argc - 1 || optind == argc) 326 usage(); 327 device_name = blkid_get_devname(NULL, argv[optind], NULL); 328 if (!device_name) { 329 com_err(program_name, 0, _("Unable to resolve '%s'"), 330 argv[optind]); 331 exit(1); 332 } 333 } 334 335 static void get_root_type(ext2_filsys fs) 336 { 337 errcode_t retval; 338 struct mem_file file; 339 char *buf; 340 struct fs_info fs_info; 341 int ret; 342 343 retval = get_file(fs, "/etc/fstab", &file); 344 if (retval) { 345 com_err(program_name, retval, "couldn't open /etc/fstab"); 346 exit(1); 347 } 348 349 while (!mem_file_eof(&file)) { 350 buf = get_line(&file); 351 if (!buf) 352 continue; 353 354 ret = parse_fstab_line(buf, &fs_info); 355 if (ret < 0) 356 goto next_line; 357 358 if (!strcmp(fs_info.mountpt, "/")) 359 printf("%s\n", fs_info.type); 360 361 free_fstab_line(&fs_info); 362 363 next_line: 364 free(buf); 365 } 366 } 367 368 369 int main (int argc, char ** argv) 370 { 371 errcode_t retval; 372 ext2_filsys fs; 373 io_manager io_ptr; 374 375 add_error_table(&et_ext2_error_table); 376 377 blkid_get_cache(&cache, NULL); 378 PRS(argc, argv); 379 380 #ifdef CONFIG_TESTIO_DEBUG 381 if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { 382 io_ptr = test_io_manager; 383 test_io_backing_manager = unix_io_manager; 384 } else 385 #endif 386 io_ptr = unix_io_manager; 387 retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs); 388 if (retval) 389 exit(1); 390 391 if (root_type) 392 get_root_type(fs); 393 394 remove_error_table(&et_ext2_error_table); 395 return (ext2fs_close (fs) ? 1 : 0); 396 } 397