/* parttool.c - common dispatcher and parser for partition operations */ /* * VAS_EBOOT -- 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 #include #include VAS_EBOOT_MOD_LICENSE ("GPLv2+"); static struct VasEBoot_parttool *parts = 0; static int curhandle = 0; static VasEBoot_dl_t mymod; static char helpmsg[] = N_("Perform COMMANDS on partition.\n" "Use `parttool PARTITION help' for the list " "of available commands."); int VasEBoot_parttool_register(const char *part_name, const VasEBoot_parttool_function_t func, const struct VasEBoot_parttool_argdesc *args) { struct VasEBoot_parttool *cur; int nargs = 0; if (! parts) VasEBoot_dl_ref (mymod); cur = (struct VasEBoot_parttool *) VasEBoot_malloc (sizeof (struct VasEBoot_parttool)); cur->next = parts; cur->name = VasEBoot_strdup (part_name); cur->handle = curhandle++; for (nargs = 0; args[nargs].name != 0; nargs++); cur->nargs = nargs; cur->args = (struct VasEBoot_parttool_argdesc *) VasEBoot_calloc (nargs + 1, sizeof (struct VasEBoot_parttool_argdesc)); if (!cur->args) { VasEBoot_free (cur); curhandle--; return -1; } VasEBoot_memcpy (cur->args, args, (nargs + 1) * sizeof (struct VasEBoot_parttool_argdesc)); cur->func = func; parts = cur; return cur->handle; } void VasEBoot_parttool_unregister (int handle) { struct VasEBoot_parttool *prev = 0, *cur, *t; for (cur = parts; cur; ) if (cur->handle == handle) { VasEBoot_free (cur->args); VasEBoot_free (cur->name); if (prev) prev->next = cur->next; else parts = cur->next; t = cur; cur = cur->next; VasEBoot_free (t); } else { prev = cur; cur = cur->next; } if (! parts) VasEBoot_dl_unref (mymod); } static VasEBoot_err_t show_help (VasEBoot_device_t dev) { int found = 0; struct VasEBoot_parttool *cur; for (cur = parts; cur; cur = cur->next) if (VasEBoot_strcmp (dev->disk->partition->partmap->name, cur->name) == 0) { struct VasEBoot_parttool_argdesc *curarg; found = 1; for (curarg = cur->args; curarg->name; curarg++) { int spacing = 20; spacing -= VasEBoot_strlen (curarg->name); VasEBoot_printf ("%s", curarg->name); switch (curarg->type) { case VAS_EBOOT_PARTTOOL_ARG_BOOL: VasEBoot_printf ("+/-"); spacing -= 3; break; case VAS_EBOOT_PARTTOOL_ARG_VAL: VasEBoot_xputs (_("=VAL")); spacing -= 4; break; case VAS_EBOOT_PARTTOOL_ARG_END: break; } while (spacing-- > 0) VasEBoot_printf (" "); VasEBoot_puts_ (curarg->desc); } } if (! found) VasEBoot_printf_ (N_("Sorry, no parttool is available for %s\n"), dev->disk->partition->partmap->name); return VAS_EBOOT_ERR_NONE; } static VasEBoot_err_t VasEBoot_cmd_parttool (VasEBoot_command_t cmd __attribute__ ((unused)), int argc, char **args) { VasEBoot_device_t dev; struct VasEBoot_parttool *cur, *ptool; int *parsed; int i, j; VasEBoot_err_t err = VAS_EBOOT_ERR_NONE; if (argc < 1) { VasEBoot_puts_ (helpmsg); return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, "too few arguments"); } if (args[0][0] == '(' && args[0][VasEBoot_strlen (args[0]) - 1] == ')') { args[0][VasEBoot_strlen (args[0]) - 1] = 0; dev = VasEBoot_device_open (args[0] + 1); args[0][VasEBoot_strlen (args[0]) - 1] = ')'; } else dev = VasEBoot_device_open (args[0]); if (! dev) return VasEBoot_errno; if (! dev->disk) { VasEBoot_device_close (dev); return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, "not a disk"); } if (! dev->disk->partition) { VasEBoot_device_close (dev); return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, "not a partition"); } /* Load modules. */ if (! VasEBoot_no_modules) { const char *prefix; prefix = VasEBoot_env_get ("prefix"); if (prefix) { char *filename; filename = VasEBoot_xasprintf ("%s/" VAS_EBOOT_TARGET_CPU "-" VAS_EBOOT_PLATFORM "/parttool.lst", prefix); if (filename) { VasEBoot_file_t file; file = VasEBoot_file_open (filename, VAS_EBOOT_FILE_TYPE_VAS_EBOOT_MODULE_LIST); if (file) { char *buf = 0; for (;; VasEBoot_free(buf)) { char *p, *name; buf = VasEBoot_file_getline (file); if (! buf) break; name = buf; while (VasEBoot_isspace (name[0])) name++; if (! VasEBoot_isgraph (name[0])) continue; p = VasEBoot_strchr (name, ':'); if (! p) continue; *p = '\0'; p++; while (*p == ' ' || *p == '\t') p++; if (! VasEBoot_isgraph (*p)) continue; if (VasEBoot_strcmp (name, dev->disk->partition->partmap->name) != 0) continue; VasEBoot_dl_load (p); } VasEBoot_file_close (file); } VasEBoot_free (filename); } } /* Ignore errors. */ VasEBoot_errno = VAS_EBOOT_ERR_NONE; } if (argc == 1) { err = show_help (dev); VasEBoot_device_close (dev); return err; } for (i = 1; i < argc; i++) if (VasEBoot_strcmp (args[i], "help") == 0) { err = show_help (dev); VasEBoot_device_close (dev); return err; } parsed = (int *) VasEBoot_calloc (argc, sizeof (int)); for (i = 1; i < argc; i++) if (! parsed[i]) { struct VasEBoot_parttool_argdesc *curarg; struct VasEBoot_parttool_args *pargs; for (cur = parts; cur; cur = cur->next) if (VasEBoot_strcmp (dev->disk->partition->partmap->name, cur->name) == 0) { for (curarg = cur->args; curarg->name; curarg++) if (VasEBoot_strncmp (curarg->name, args[i], VasEBoot_strlen (curarg->name)) == 0 && ((curarg->type == VAS_EBOOT_PARTTOOL_ARG_BOOL && (args[i][VasEBoot_strlen (curarg->name)] == '+' || args[i][VasEBoot_strlen (curarg->name)] == '-' || args[i][VasEBoot_strlen (curarg->name)] == 0)) || (curarg->type == VAS_EBOOT_PARTTOOL_ARG_VAL && args[i][VasEBoot_strlen (curarg->name)] == '='))) break; if (curarg->name) break; } if (! cur) { VasEBoot_free (parsed); VasEBoot_device_close (dev); return VasEBoot_error (VAS_EBOOT_ERR_BAD_ARGUMENT, N_("unknown argument `%s'"), args[i]); } ptool = cur; pargs = (struct VasEBoot_parttool_args *) VasEBoot_calloc (ptool->nargs, sizeof (struct VasEBoot_parttool_args)); for (j = i; j < argc; j++) if (! parsed[j]) { for (curarg = ptool->args; curarg->name; curarg++) if (VasEBoot_strncmp (curarg->name, args[j], VasEBoot_strlen (curarg->name)) == 0 && ((curarg->type == VAS_EBOOT_PARTTOOL_ARG_BOOL && (args[j][VasEBoot_strlen (curarg->name)] == '+' || args[j][VasEBoot_strlen (curarg->name)] == '-' || args[j][VasEBoot_strlen (curarg->name)] == 0)) || (curarg->type == VAS_EBOOT_PARTTOOL_ARG_VAL && args[j][VasEBoot_strlen (curarg->name)] == '='))) { parsed[j] = 1; pargs[curarg - ptool->args].set = 1; switch (curarg->type) { case VAS_EBOOT_PARTTOOL_ARG_BOOL: pargs[curarg - ptool->args].b = (args[j][VasEBoot_strlen (curarg->name)] != '-'); break; case VAS_EBOOT_PARTTOOL_ARG_VAL: pargs[curarg - ptool->args].str = (args[j] + VasEBoot_strlen (curarg->name) + 1); break; case VAS_EBOOT_PARTTOOL_ARG_END: break; } } } err = ptool->func (dev, pargs); VasEBoot_free (pargs); if (err) break; } VasEBoot_free (parsed); VasEBoot_device_close (dev); return err; } static VasEBoot_command_t cmd; VAS_EBOOT_MOD_INIT(parttool) { mymod = mod; cmd = VasEBoot_register_command ("parttool", VasEBoot_cmd_parttool, N_("PARTITION COMMANDS"), helpmsg); } VAS_EBOOT_MOD_FINI(parttool) { VasEBoot_unregister_command (cmd); }