diff options
Diffstat (limited to '')
-rw-r--r-- | misc/e2initrd_helper.c | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/misc/e2initrd_helper.c b/misc/e2initrd_helper.c new file mode 100644 index 0000000..b39fe15 --- /dev/null +++ b/misc/e2initrd_helper.c @@ -0,0 +1,398 @@ +/* + * 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 "support/devname.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 = 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 = 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); +} |