| /* |
| * 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 "../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); |
| } |