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