diff options
Diffstat (limited to 'tools/libfsimage/common/fsimage_grub.c')
-rw-r--r-- | tools/libfsimage/common/fsimage_grub.c | 276 |
1 files changed, 276 insertions, 0 deletions
diff --git a/tools/libfsimage/common/fsimage_grub.c b/tools/libfsimage/common/fsimage_grub.c new file mode 100644 index 0000000000..252445f58e --- /dev/null +++ b/tools/libfsimage/common/fsimage_grub.c @@ -0,0 +1,276 @@ +/* + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +#ifndef __sun__ +#define _XOPEN_SOURCE 500 +#endif +#include <stdlib.h> +#include <strings.h> +#include <errno.h> + +#include "fsimage_grub.h" +#include "fsimage_priv.h" + +static char *disk_read_junk; + +typedef struct fsig_data { + char fd_buf[FSYS_BUFLEN]; +} fsig_data_t; + +typedef struct fsig_file_data { + char ffd_buf[FSYS_BUFLEN]; + uint64_t ffd_curpos; + uint64_t ffd_filepos; + uint64_t ffd_filemax; + int ffd_int1; + int ffd_int2; + int ffd_errnum; +} fsig_file_data_t; + +fsi_file_t * +fsig_file_alloc(fsi_t *fsi) +{ + fsi_file_t *ffi; + fsig_file_data_t *data = malloc(sizeof (fsig_file_data_t)); + + if (data == NULL) + return (NULL); + + bzero(data, sizeof (fsig_file_data_t)); + bcopy(fsig_fs_buf(fsi), data->ffd_buf, FSYS_BUFLEN); + + if ((ffi = fsip_file_alloc(fsi, data)) == NULL) { + free(data); + return (NULL); + } + + return (ffi); +} + +void * +fsig_fs_buf(fsi_t *fsi) +{ + fsig_data_t *data = fsip_fs_data(fsi); + return ((void *)data->fd_buf); +} + +void * +fsig_file_buf(fsi_file_t *ffi) +{ + fsig_file_data_t *data = fsip_file_data(ffi); + return ((void *)data->ffd_buf); +} + +uint64_t * +fsig_filepos(fsi_file_t *ffi) +{ + fsig_file_data_t *data = fsip_file_data(ffi); + return (&data->ffd_filepos); +} + +uint64_t * +fsig_filemax(fsi_file_t *ffi) +{ + fsig_file_data_t *data = fsip_file_data(ffi); + return (&data->ffd_filemax); +} + +int * +fsig_int1(fsi_file_t *ffi) +{ + fsig_file_data_t *data = fsip_file_data(ffi); + return (&data->ffd_int1); +} + +int * +fsig_int2(fsi_file_t *ffi) +{ + fsig_file_data_t *data = fsip_file_data(ffi); + return (&data->ffd_int2); +} + +int * +fsig_errnum(fsi_file_t *ffi) +{ + fsig_file_data_t *data = fsip_file_data(ffi); + return (&data->ffd_errnum); +} + +char ** +fsig_disk_read_junk(void) +{ + return (&disk_read_junk); +} + +int +fsig_devread(fsi_file_t *ffi, unsigned int sector, unsigned int offset, + unsigned int bufsize, char *buf) +{ + uint64_t off = ffi->ff_fsi->f_off + ((uint64_t)sector * 512) + offset; + ssize_t bytes_read = 0; + + while (bufsize) { + ssize_t ret = pread(ffi->ff_fsi->f_fd, buf + bytes_read, + bufsize, (off_t)off); + if (ret == -1) + return (0); + if (ret == 0) + return (0); + + bytes_read += ret; + bufsize -= ret; + } + + return (1); +} + +int +fsig_substring(const char *s1, const char *s2) +{ + while (*s1 == *s2) { + if (*s1 == '\0') + return (0); + s1++; + s2++; + } + + if (*s1 == '\0') + return (-1); + + return (1); +} + +static int +fsig_mount(fsi_t *fsi, const char *path) +{ + fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data; + fsi_file_t *ffi; + fsi->f_data = malloc(sizeof (fsig_data_t)); + + if (fsi->f_data == NULL) + return (-1); + + if ((ffi = fsig_file_alloc(fsi)) == NULL) { + free(fsi->f_data); + fsi->f_data = NULL; + return (-1); + } + + bzero(fsi->f_data, sizeof (fsig_data_t)); + + if (!ops->fpo_mount(ffi)) { + fsip_file_free(ffi); + free(fsi->f_data); + fsi->f_data = NULL; + return (-1); + } + + bcopy(fsig_file_buf(ffi), fsig_fs_buf(fsi), FSYS_BUFLEN); + fsip_file_free(ffi); + return (0); +} + +static int +fsig_umount(fsi_t *fsi) +{ + return (0); +} + +static fsi_file_t * +fsig_open(fsi_t *fsi, const char *name) +{ + fsig_plugin_ops_t *ops = fsi->f_plugin->fp_data; + char *path = strdup(name); + fsi_file_t *ffi = NULL; + + if (path == NULL || (ffi = fsig_file_alloc(fsi)) == NULL) + goto out; + + if (ops->fpo_dir(ffi, path) == 0) { + fsip_file_free(ffi); + ffi = NULL; + errno = ENOENT; + } + +out: + free(path); + return (ffi); +} + +static ssize_t +fsig_pread(fsi_file_t *ffi, void *buf, size_t nbytes, uint64_t off) +{ + fsig_plugin_ops_t *ops = ffi->ff_fsi->f_plugin->fp_data; + fsig_file_data_t *data = fsip_file_data(ffi); + + data->ffd_filepos = off; + + if (data->ffd_filepos >= data->ffd_filemax) + return (0); + + /* FIXME: check */ + if (data->ffd_filepos + nbytes > data->ffd_filemax) + nbytes = data->ffd_filemax - data->ffd_filepos; + + errnum = 0; + return (ops->fpo_read(ffi, buf, nbytes)); +} + +static ssize_t +fsig_read(fsi_file_t *ffi, void *buf, size_t nbytes) +{ + fsig_file_data_t *data = fsip_file_data(ffi); + ssize_t ret; + + ret = fsig_pread(ffi, buf, nbytes, data->ffd_curpos); + data->ffd_curpos = data->ffd_filepos; + return (ret); +} + +static int +fsig_close(fsi_file_t *ffi) +{ + fsip_file_free(ffi); + return (0); +} + +static fsi_plugin_ops_t fsig_grub_ops = { + .fpo_version = FSIMAGE_PLUGIN_VERSION, + .fpo_mount = fsig_mount, + .fpo_umount = fsig_umount, + .fpo_open = fsig_open, + .fpo_read = fsig_read, + .fpo_pread = fsig_pread, + .fpo_close = fsig_close +}; + +fsi_plugin_ops_t * +fsig_init(fsi_plugin_t *plugin, fsig_plugin_ops_t *ops) +{ + if (ops->fpo_version > FSIMAGE_PLUGIN_VERSION) + return (NULL); + + plugin->fp_data = ops; + + return (&fsig_grub_ops); +} |