/* * e2initrd_helper.c - Get the filesystem table * * Copyright 2004 by Theodore Ts'o. * * %Begin-Header% * This file may be redistributed under the terms of the GNU Public * License. * %End-Header% */ #include <stdio.h> #include <unistd.h> #ifdef HAVE_STDLIB_H #include <stdlib.h> #endif #include <ctype.h> #include <string.h> #include <time.h> #ifdef HAVE_ERRNO_H #include <errno.h> #endif #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <utime.h> #ifdef HAVE_GETOPT_H #include <getopt.h> #else extern int optind; extern char *optarg; #endif #include "ext2fs/ext2_fs.h" #include "ext2fs/ext2fs.h" #include "blkid/blkid.h" #include "../version.h" #include "nls-enable.h" static const char * program_name = "e2initrd_helper"; static char * device_name; static int open_flag; static int root_type; static blkid_cache cache = NULL; struct mem_file { char *buf; int size; int ptr; }; struct fs_info { char *device; char *mountpt; char *type; char *opts; int freq; int passno; int flags; struct fs_info *next; }; static void usage(void) { fprintf(stderr, _("Usage: %s -r device\n"), program_name); exit (1); } static errcode_t get_file(ext2_filsys fs, const char * filename, struct mem_file *ret_file) { errcode_t retval; char *buf; ext2_file_t e2_file = NULL; unsigned int got; struct ext2_inode inode; ext2_ino_t ino; ret_file->buf = 0; ret_file->size = 0; ret_file->ptr = 0; retval = ext2fs_namei(fs, EXT2_ROOT_INO, EXT2_ROOT_INO, filename, &ino); if (retval) return retval; retval = ext2fs_read_inode(fs, ino, &inode); if (retval) return retval; if (inode.i_size_high || (inode.i_size > 65536)) return EFBIG; buf = malloc(inode.i_size + 1); if (!buf) return ENOMEM; memset(buf, 0, inode.i_size+1); retval = ext2fs_file_open(fs, ino, 0, &e2_file); if (retval) goto errout; retval = ext2fs_file_read(e2_file, buf, inode.i_size, &got); if (retval) goto errout; retval = ext2fs_file_close(e2_file); if (retval) goto errout; ret_file->buf = buf; ret_file->size = (int) got; return 0; errout: free(buf); if (e2_file) ext2fs_file_close(e2_file); return retval; } static char *get_line(struct mem_file *file) { char *cp, *ret; int s = 0; cp = file->buf + file->ptr; while (*cp && *cp != '\n') { cp++; s++; } ret = malloc(s+1); if (!ret) return 0; ret[s]=0; memcpy(ret, file->buf + file->ptr, s); while (*cp && (*cp == '\n' || *cp == '\r')) { cp++; s++; } file->ptr += s; return ret; } static int mem_file_eof(struct mem_file *file) { return (file->ptr >= file->size); } /* * fstab parsing code */ static char *string_copy(const char *s) { char *ret; if (!s) return 0; ret = malloc(strlen(s)+1); if (ret) strcpy(ret, s); return ret; } static char *skip_over_blank(char *cp) { while (*cp && isspace(*cp)) cp++; return cp; } static char *skip_over_word(char *cp) { while (*cp && !isspace(*cp)) cp++; return cp; } static char *parse_word(char **buf) { char *word, *next; word = *buf; if (*word == 0) return 0; word = skip_over_blank(word); next = skip_over_word(word); if (*next) *next++ = 0; *buf = next; return word; } static void parse_escape(char *word) { char *p, *q; int ac, i; if (!word) return; for (p = word, q = word; *p; p++, q++) { *q = *p; if (*p != '\\') continue; if (*++p == 0) break; if (*p == 't') { *q = '\t'; continue; } if (*p == 'n') { *q = '\n'; continue; } if (!isdigit(*p)) { *q = *p; continue; } ac = 0; for (i = 0; i < 3; i++, p++) { if (!isdigit(*p)) break; ac = (ac * 8) + (*p - '0'); } *q = ac; p--; } *q = 0; } static int parse_fstab_line(char *line, struct fs_info *fs) { char *dev, *device, *mntpnt, *type, *opts, *freq, *passno, *cp; if ((cp = strchr(line, '#'))) *cp = 0; /* Ignore everything after the comment char */ cp = line; device = parse_word(&cp); mntpnt = parse_word(&cp); type = parse_word(&cp); opts = parse_word(&cp); freq = parse_word(&cp); passno = parse_word(&cp); if (!device) return -1; /* Allow blank lines */ if (!mntpnt || !type) return -1; parse_escape(device); parse_escape(mntpnt); parse_escape(type); parse_escape(opts); parse_escape(freq); parse_escape(passno); dev = blkid_get_devname(cache, device, NULL); if (dev) device = dev; if (strchr(type, ',')) type = 0; fs->device = string_copy(device); fs->mountpt = string_copy(mntpnt); fs->type = string_copy(type); fs->opts = string_copy(opts ? opts : ""); fs->freq = freq ? atoi(freq) : -1; fs->passno = passno ? atoi(passno) : -1; fs->flags = 0; fs->next = NULL; free(dev); return 0; } static void free_fstab_line(struct fs_info *fs) { if (fs->device) fs->device = 0; if (fs->mountpt) fs->mountpt = 0; if (fs->type) fs->type = 0; if (fs->opts) fs->opts = 0; memset(fs, 0, sizeof(struct fs_info)); } static void PRS(int argc, char **argv) { int c; #ifdef ENABLE_NLS setlocale(LC_MESSAGES, ""); setlocale(LC_CTYPE, ""); bindtextdomain(NLS_CAT_NAME, LOCALEDIR); textdomain(NLS_CAT_NAME); set_com_err_gettext(gettext); #endif while ((c = getopt(argc, argv, "rv")) != EOF) { switch (c) { case 'r': root_type++; break; case 'v': printf("%s %s (%s)\n", program_name, E2FSPROGS_VERSION, E2FSPROGS_DATE); break; default: usage(); } } if (optind < argc - 1 || optind == argc) usage(); device_name = blkid_get_devname(NULL, argv[optind], NULL); if (!device_name) { com_err(program_name, 0, _("Unable to resolve '%s'"), argv[optind]); exit(1); } } static void get_root_type(ext2_filsys fs) { errcode_t retval; struct mem_file file; char *buf; struct fs_info fs_info; int ret; retval = get_file(fs, "/etc/fstab", &file); if (retval) { com_err(program_name, retval, "couldn't open /etc/fstab"); exit(1); } while (!mem_file_eof(&file)) { buf = get_line(&file); if (!buf) continue; ret = parse_fstab_line(buf, &fs_info); if (ret < 0) goto next_line; if (!strcmp(fs_info.mountpt, "/")) printf("%s\n", fs_info.type); free_fstab_line(&fs_info); next_line: free(buf); } } int main (int argc, char ** argv) { errcode_t retval; ext2_filsys fs; io_manager io_ptr; add_error_table(&et_ext2_error_table); blkid_get_cache(&cache, NULL); PRS(argc, argv); #ifdef CONFIG_TESTIO_DEBUG if (getenv("TEST_IO_FLAGS") || getenv("TEST_IO_BLOCK")) { io_ptr = test_io_manager; test_io_backing_manager = unix_io_manager; } else #endif io_ptr = unix_io_manager; retval = ext2fs_open (device_name, open_flag, 0, 0, io_ptr, &fs); if (retval) exit(1); if (root_type) get_root_type(fs); remove_error_table(&et_ext2_error_table); return (ext2fs_close (fs) ? 1 : 0); }