| /* | |
| * 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 "config.h" | |
| #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 "support/nls-enable.h" | |
| #include "../version.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); | |
| } |