diff --git a/ChangeLog b/ChangeLog index e3ac3ac..5fc3e37 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,20 @@ 2009-03-15 Vladimir Serbinenko + + Parttool + + * parttool/pcpart.c: new file + * commands/parttool.c: likewise + * conf/common.rmk: Added parttool.mod and pcpart.mod + * conf/i386-coreboot.rmk: added commands/parttool.c + and parttool/pcpart.c to grub-emu + * conf/i386-efi.rmk: likewise + * conf/i386-ieee1275.rmk: likewise + * conf/i386-pc.rmk: likewise + * conf/powerpc-ieee1275.rmk: likewise + * conf/sparc64-ieee1275.rmk: likewise + * conf/x86_64-ieee1275.rmk: likewise + +2009-03-15 Vladimir Serbinenko Efiemu diff --git a/commands/parttool.c b/commands/parttool.c new file mode 100644 index 0000000..fb6bdaa --- /dev/null +++ b/commands/parttool.c @@ -0,0 +1,261 @@ +/* parttool.c - common dispatcher and parser for partition operations */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct grub_parttool *parts = 0; +static int curhandle = 0; +static grub_dl_t mymod; + +int +grub_parttool_register(const char *part_name, + const grub_parttool_function_t func, + const struct grub_parttool_argdesc *args) +{ + struct grub_parttool *cur; + int nargs = 0; + struct grub_parttool_argdesc *curarg; + +#ifndef GRUB_UTIL + if (!parts) + grub_dl_ref (mymod); +#endif + + cur = (struct grub_parttool *) grub_malloc (sizeof (struct grub_parttool)); + cur->next = parts; + cur->name = grub_strdup (part_name); + cur->handle = curhandle++; + for (curarg = args; curarg->name != 0; curarg++) + nargs++; + cur->nargs = nargs; + cur->args = (struct grub_parttool_argdesc *) + grub_malloc ((nargs + 1) * sizeof (struct grub_parttool_argdesc)); + grub_memcpy (cur->args, args, + (nargs + 1) * sizeof (struct grub_parttool_argdesc)); + + cur->func = func; + parts = cur; + return cur->handle; +} + +void +grub_parttool_unregister (int handle) +{ + struct grub_parttool *prev = 0, *cur, *t; + for (cur = parts; cur; ) + if (cur->handle == handle) + { + grub_free (cur->args); + grub_free (cur->name); + if (prev) + prev->next = cur->next; + else + parts = cur->next; + t = cur; + cur = cur->next; + grub_free (t); + } + else + { + prev = cur; + cur = cur->next; + } +#ifndef GRUB_UTIL + if (!parts) + grub_dl_unref (mymod); +#endif +} + +static grub_err_t +grub_cmd_parttool (struct grub_arg_list *state __attribute__ ((unused)), + int argc, char **args) +{ + grub_device_t dev; + struct grub_parttool *cur, *ptool; + int *parsed; + int i, j; + grub_err_t err = GRUB_ERR_NONE; + + if (argc < 2) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few arguments"); + + if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')') + { + args[0][grub_strlen (args[0])-1] = 0; + args[0]++; + } + + dev = grub_device_open (args[0]); + + if (!dev) + return grub_errno; + + if (!dev->disk) + { + grub_device_close (dev); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk"); + } + + if (!dev->disk->partition) + { + grub_device_close (dev); + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a partition"); + } + + parsed = (int *)grub_malloc (argc * sizeof (int)); + grub_memset (parsed, 0, argc * sizeof (int)); + + for (i = 1; i < argc; i++) + if (!grub_strcmp (args[i], "help")) + { + int found = 0; + for (cur = parts; cur; cur = cur->next) + if (!grub_strcmp (dev->disk->partition->partmap->name, cur->name)) + { + struct grub_parttool_argdesc *curarg; + found = 1; + for (curarg = cur->args; curarg->name; curarg++) + { + int spacing = 20; + + spacing -= grub_strlen (curarg->name); + grub_printf ("%s", curarg->name); + + switch (curarg->type) + { + case GRUB_PARTTOOL_ARG_BOOL: + grub_printf ("+/-"); + spacing-=3; + break; + + case GRUB_PARTTOOL_ARG_VAL: + grub_printf ("=VAL"); + spacing-=4; + break; + + case GRUB_PARTTOOL_ARG_END: + break; + } + while (spacing-- > 0) + grub_printf (" "); + grub_printf ("%s\n", curarg->desc); + } + } + if (!found) + grub_printf ("Sorry no parttool is available for %s\n", + dev->disk->partition->partmap->name); + return GRUB_ERR_NONE; + } + + for (i = 1; i < argc; i++) + if (!parsed[i]) + { + struct grub_parttool_argdesc *curarg; + struct grub_parttool_args *pargs; + for (cur = parts; cur; cur = cur->next) + if (!grub_strcmp (dev->disk->partition->partmap->name, cur->name)) + { + for (curarg = cur->args; curarg->name; curarg++) + if (!grub_strncmp (curarg->name, args[i], + grub_strlen (curarg->name)) + && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL + && (args[i][grub_strlen (curarg->name)] == '+' + || args[i][grub_strlen (curarg->name)] == '-')) + || (curarg->type==GRUB_PARTTOOL_ARG_VAL + && args[i][grub_strlen (curarg->name)] == '='))) + + break; + if (curarg->name) + break; + } + if (!cur) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "unrecognised argument %s", + args[i]); + ptool = cur; + pargs = (struct grub_parttool_args *) + grub_malloc (ptool->nargs * sizeof (struct grub_parttool_args)); + grub_memset (pargs, 0, + ptool->nargs * sizeof (struct grub_parttool_args)); + for (j = i; j < argc; j++) + if (!parsed[j]) + { + for (curarg = ptool->args; curarg->name; curarg++) + if (!grub_strncmp (curarg->name, args[i], + grub_strlen (curarg->name)) + && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL + && (args[j][grub_strlen (curarg->name)] == '+' + || args[j][grub_strlen (curarg->name)] == '-')) + || (curarg->type == GRUB_PARTTOOL_ARG_VAL + && args[j][grub_strlen (curarg->name)] == '='))) + { + parsed[j] = 1; + pargs[curarg - ptool->args].set = 1; + switch (curarg->type) + { + case GRUB_PARTTOOL_ARG_BOOL: + pargs[curarg - ptool->args].bool + = (args[j][grub_strlen (curarg->name)] != '-'); + break; + + case GRUB_PARTTOOL_ARG_VAL: + pargs[curarg - ptool->args].str + = (args[j]+grub_strlen (curarg->name)+ 1); + break; + + case GRUB_PARTTOOL_ARG_END: + break; + } + } + } + + err = ptool->func (dev, pargs); + grub_free (pargs); + if (err) + break; + } + + grub_device_close (dev); + return err; +} + +GRUB_MOD_INIT(parttool) +{ + (void)mod; /* To stop warning. */ + mymod = mod; + grub_register_command ("parttool", grub_cmd_parttool, GRUB_COMMAND_FLAG_BOTH, + "parttool PARTITION COMMANDS", + "perform COMMANDS on partition." + " use parttool PARTITION help for the list " + " of available commands", 0); +} + +GRUB_MOD_FINI(parttool) +{ + grub_unregister_command ("parttool"); +} diff --git a/conf/common.rmk b/conf/common.rmk index 857d8b8..100fae7 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -334,7 +334,7 @@ pkglib_MODULES += hello.mod boot.mod handler.mod ls.mod \ cmp.mod cat.mod help.mod search.mod \ loopback.mod fs_uuid.mod configfile.mod echo.mod \ terminfo.mod test.mod blocklist.mod hexdump.mod \ - read.mod sleep.mod loadenv.mod crc.mod + read.mod sleep.mod loadenv.mod crc.mod parttool.mod pcpart.mod # For hello.mod. hello_mod_SOURCES = hello/hello.c @@ -346,6 +346,16 @@ boot_mod_SOURCES = commands/boot.c boot_mod_CFLAGS = $(COMMON_CFLAGS) boot_mod_LDFLAGS = $(COMMON_LDFLAGS) +# For parttool.mod. +parttool_mod_SOURCES = commands/parttool.c +parttool_mod_CFLAGS = $(COMMON_CFLAGS) +parttool_mod_LDFLAGS = $(COMMON_LDFLAGS) + +# For pcpart.mod. +pcpart_mod_SOURCES = parttool/pcpart.c +pcpart_mod_CFLAGS = $(COMMON_CFLAGS) +pcpart_mod_LDFLAGS = $(COMMON_LDFLAGS) + # For handler.mod. handler_mod_SOURCES = commands/handler.c handler_mod_CFLAGS = $(COMMON_CFLAGS) diff --git a/conf/i386-coreboot.rmk b/conf/i386-coreboot.rmk index 33b798c..ddcc308 100644 --- a/conf/i386-coreboot.rmk +++ b/conf/i386-coreboot.rmk @@ -89,6 +89,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ \ disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ + commands/parttool.c parttool/pcpart.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/i386-efi.rmk b/conf/i386-efi.rmk index f9380d1..a2454d9 100644 --- a/conf/i386-efi.rmk +++ b/conf/i386-efi.rmk @@ -66,6 +66,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ \ disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ + commands/parttool.c parttool/pcpart.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index d5e1fab..3a00d17 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -152,6 +152,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ efiemu/modules/pnvram.c efiemu/i386/loadcore32.c \ efiemu/i386/loadcore64.c efiemu/symbols.c efiemu/prepare32.c \ efiemu/prepare64.c efiemu/uppermem.c lib/crc.c \ + commands/parttool.c parttool/pcpart.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/i386.rmk b/conf/i386.rmk index 9ae65ae..4e86ed8 100644 --- a/conf/i386.rmk +++ b/conf/i386.rmk @@ -19,13 +19,3 @@ pkglib_MODULES += uppermem.mod uppermem_mod_SOURCES = lib/i386/uppermem.c uppermem_mod_CFLAGS = $(COMMON_CFLAGS) uppermem_mod_LDFLAGS = $(COMMON_LDFLAGS) - -pkglib_MODULES += xnu.mod _xnu.mod -_xnu_mod_SOURCES = loader/xnu_resume.c loader/i386/xnu.c loader/macho.c loader/xnu.c loader/xnu_rescue.c loader/i386/xnu_helper.S -_xnu_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall -_xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) -_xnu_mod_ASFLAGS = $(COMMON_ASFLAGS) - -xnu_mod_SOURCES = loader/xnu_normal.c -xnu_mod_CFLAGS = $(COMMON_CFLAGS) -Werror -Wall -xnu_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/powerpc-ieee1275.rmk b/conf/powerpc-ieee1275.rmk index f33d19a..66d1d58 100644 --- a/conf/powerpc-ieee1275.rmk +++ b/conf/powerpc-ieee1275.rmk @@ -70,6 +70,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ \ disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ + commands/parttool.c parttool/pcpart.c \ grub_script.tab.c grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/sparc64-ieee1275.rmk b/conf/sparc64-ieee1275.rmk index 75cc1f4..0794dc0 100644 --- a/conf/sparc64-ieee1275.rmk +++ b/conf/sparc64-ieee1275.rmk @@ -67,6 +67,7 @@ grub_mkimage_SOURCES = util/sparc64/ieee1275/grub-mkimage.c util/misc.c \ # partmap/acorn.c \ # util/console.c util/grub-emu.c util/misc.c \ # util/hostdisk.c util/getroot.c \ +# commands/parttool.c parttool/pcpart.c \ # util/sparc64/ieee1275/misc.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/conf/x86_64-efi.rmk b/conf/x86_64-efi.rmk index ebbfb23..fb7bb32 100644 --- a/conf/x86_64-efi.rmk +++ b/conf/x86_64-efi.rmk @@ -68,6 +68,7 @@ grub_emu_SOURCES = commands/boot.c commands/cat.c commands/cmp.c \ \ disk/raid.c disk/raid5_recover.c disk/raid6_recover.c \ disk/mdraid_linux.c disk/dmraid_nvidia.c disk/lvm.c \ + commands/parttool.c parttool/pcpart.c \ grub_emu_init.c grub_emu_LDFLAGS = $(LIBCURSES) diff --git a/include/grub/parttool.h b/include/grub/parttool.h new file mode 100644 index 0000000..0e05f4c --- /dev/null +++ b/include/grub/parttool.h @@ -0,0 +1,58 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#ifndef GRUB_PARTTOOL_HEADER +#define GRUB_PARTTOOL_HEADER 1 + +struct grub_parttool_argdesc +{ + char *name; + char *desc; + enum {GRUB_PARTTOOL_ARG_END, GRUB_PARTTOOL_ARG_BOOL, GRUB_PARTTOOL_ARG_VAL} + type; +}; + +struct grub_parttool_args +{ + int set; + union + { + int bool; + char *str; + }; +}; + +typedef grub_err_t (*grub_parttool_function_t) (const grub_device_t dev, + const struct grub_parttool_args *args); + +struct grub_parttool +{ + struct grub_parttool *next; + char *name; + int handle; + int nargs; + struct grub_parttool_argdesc *args; + grub_parttool_function_t func; +}; + +int grub_parttool_register(const char *part_name, + const grub_parttool_function_t func, + const struct grub_parttool_argdesc *args); +void grub_parttool_unregister (int handle); + +#endif /* ! GRUB_PARTTOOL_HEADER*/ diff --git a/parttool/pcpart.c b/parttool/pcpart.c new file mode 100644 index 0000000..53e6403 --- /dev/null +++ b/parttool/pcpart.c @@ -0,0 +1,152 @@ +/* pcpart.c - manipulate fdisk partitions */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int activate_table_handle = -1; +static int type_table_handle = -1; + +static struct grub_parttool_argdesc grub_pcpart_bootargs[] = +{ + {"boot", "Make partition active", GRUB_PARTTOOL_ARG_BOOL}, + {0, 0, 0} +}; + +static grub_err_t grub_pcpart_boot (const grub_device_t dev, + const struct grub_parttool_args *args) +{ + int i, index; + grub_partition_t part; + struct grub_pc_partition_mbr mbr; + + if (dev->disk->partition->offset) + return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a primary partition"); + + index = dev->disk->partition->index; + part = dev->disk->partition; + dev->disk->partition = 0; + + /* Read the MBR. */ + if (grub_disk_read (dev->disk, 0, 0, sizeof (mbr), (char *) &mbr)) + { + dev->disk->partition = part; + return grub_errno; + } + + if (args[0].set && args[0].bool) + { + for (i = 0; i < 4; i++) + mbr.entries[i].flag = 0x0; + mbr.entries[index].flag = 0x80; + } + else + mbr.entries[index].flag = 0x0; + + /* Write the MBR. */ + grub_disk_write (dev->disk, 0, 0, sizeof (mbr), (char *) &mbr); + + dev->disk->partition = part; + + return GRUB_ERR_NONE; +} + +static struct grub_parttool_argdesc grub_pcpart_typeargs[] = +{ + {"type", "Change partition type", GRUB_PARTTOOL_ARG_VAL}, + {"hidden", "Make partition hidden", GRUB_PARTTOOL_ARG_BOOL}, + {0, 0, 0} +}; + +static grub_err_t grub_pcpart_type (const grub_device_t dev, + const struct grub_parttool_args *args) +{ + int index; + grub_uint8_t type; + grub_partition_t part; + struct grub_pc_partition_mbr mbr; + + index = dev->disk->partition->index; + part = dev->disk->partition; + dev->disk->partition = 0; + + /* Read the parttable. */ + if (grub_disk_read (dev->disk, part->offset, 0, + sizeof (mbr), (char *) &mbr)) + { + dev->disk->partition = part; + return grub_errno; + } + + if (args[0].set) + type = grub_strtoul (args[0].str, 0, 0); + else + type = mbr.entries[index].type; + + if (args[1].set) + { + if (args[1].bool) + type |= GRUB_PC_PARTITION_TYPE_HIDDEN_FLAG; + else + type &= ~GRUB_PC_PARTITION_TYPE_HIDDEN_FLAG; + } + + if (grub_pc_partition_is_empty (type) + || grub_pc_partition_is_extended (type)) + { + dev->disk->partition = part; + return grub_error (GRUB_ERR_BAD_ARGUMENT, "invalid type"); + } + + mbr.entries[index].type = type; + + /* Write the parttable. */ + grub_disk_write (dev->disk, part->offset, 0, + sizeof (mbr), (char *) &mbr); + + dev->disk->partition = part; + + return GRUB_ERR_NONE; +} + +GRUB_MOD_INIT (pcpart) +{ + (void)mod; /* To stop warning. */ + + activate_table_handle = grub_parttool_register("pc_partition_map", + grub_pcpart_boot, + grub_pcpart_bootargs); + type_table_handle = grub_parttool_register("pc_partition_map", + grub_pcpart_type, + grub_pcpart_typeargs); + +} +GRUB_MOD_FINI(pcpart) +{ + grub_parttool_unregister (activate_table_handle); + grub_parttool_unregister (type_table_handle); +}