parttool.c 8.11 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
/* 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 <grub/types.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/err.h>
#include <grub/dl.h>
#include <grub/normal.h>
#include <grub/device.h>
#include <grub/disk.h>
#include <grub/partition.h>
#include <grub/parttool.h>
#include <grub/command.h>
32
#include <grub/i18n.h>
33

34 35
GRUB_MOD_LICENSE ("GPLv2+");

36 37 38
static struct grub_parttool *parts = 0;
static int curhandle = 0;
static grub_dl_t mymod;
39
static char helpmsg[] =
40
  N_("Perform COMMANDS on partition.\n"
41
     "Use `parttool PARTITION help' for the list "
42
     "of available commands.");
43

44 45
int
grub_parttool_register(const char *part_name,
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
		       const grub_parttool_function_t func,
		       const struct grub_parttool_argdesc *args)
{
  struct grub_parttool *cur;
  int nargs = 0;

  if (! parts)
    grub_dl_ref (mymod);

  cur = (struct grub_parttool *) grub_malloc (sizeof (struct grub_parttool));
  cur->next = parts;
  cur->name = grub_strdup (part_name);
  cur->handle = curhandle++;
  for (nargs = 0; args[nargs].name != 0; nargs++);
  cur->nargs = nargs;
61
  cur->args = (struct grub_parttool_argdesc *)
62
    grub_malloc ((nargs + 1) * sizeof (struct grub_parttool_argdesc));
63
  grub_memcpy (cur->args, args,
64
	       (nargs + 1) * sizeof (struct grub_parttool_argdesc));
65

66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96
  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;
      }
  if (! parts)
    grub_dl_unref (mymod);
}

97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
static grub_err_t
show_help (grub_device_t dev)
{
  int found = 0;
  struct grub_parttool *cur;

  for (cur = parts; cur; cur = cur->next)
    if (grub_strcmp (dev->disk->partition->partmap->name, cur->name) == 0)
      {
	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_xputs (_("=VAL"));
		spacing -= 4;
		break;

	      case GRUB_PARTTOOL_ARG_END:
		break;
	      }
	    while (spacing-- > 0)
	      grub_printf (" ");
	    grub_puts_ (curarg->desc);
	  }
      }
  if (! found)
136
    grub_printf_ (N_("Sorry, no parttool is available for %s\n"),
137 138 139 140
		  dev->disk->partition->partmap->name);
  return GRUB_ERR_NONE;
}

141 142 143 144 145 146 147 148 149 150
static grub_err_t
grub_cmd_parttool (grub_command_t cmd __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;

151 152
  if (argc < 1)
    {
153
      grub_puts_ (helpmsg);
154 155
      return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few arguments");
    }
156 157 158 159

  if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')')
    {
      args[0][grub_strlen (args[0]) - 1] = 0;
160
      dev = grub_device_open (args[0] + 1);
161 162 163
      args[0][grub_strlen (args[0]) - 1] = ')';
    }
  else
164
    dev = grub_device_open (args[0]);
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

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

181
  /* Load modules. */
182
  if (! grub_no_modules)
183 184 185 186
  {
    const char *prefix;
    prefix = grub_env_get ("prefix");
    if (prefix)
187
      {
188
	char *filename;
189

190 191
	filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM
				   "/parttool.lst", prefix);
192 193 194
	if (filename)
	  {
	    grub_file_t file;
195

196 197 198 199 200 201 202
	    file = grub_file_open (filename);
	    if (file)
	      {
		char *buf = 0;
		for (;; grub_free(buf))
		  {
		    char *p, *name;
203

204
		    buf = grub_file_getline (file);
205

206
		    if (! buf)
207
		      break;
208

209
		    name = buf;
210 211
		    while (grub_isspace (name[0]))
		      name++;
212

213 214
		    if (! grub_isgraph (name[0]))
		      continue;
215

216 217 218
		    p = grub_strchr (name, ':');
		    if (! p)
		      continue;
219

220
		    *p = '\0';
221 222 223
		    p++;
		    while (*p == ' ' || *p == '\t')
		      p++;
224 225 226

		    if (! grub_isgraph (*p))
		      continue;
227

228 229 230
		    if (grub_strcmp (name, dev->disk->partition->partmap->name)
			!= 0)
		      continue;
231

232 233
		    grub_dl_load (p);
		  }
234

235 236
		grub_file_close (file);
	      }
237

238 239
	    grub_free (filename);
	  }
240
      }
241 242 243 244 245
    /* Ignore errors.  */
    grub_errno = GRUB_ERR_NONE;
  }

  if (argc == 1)
246 247 248 249 250
    {
      err = show_help (dev);
      grub_device_close (dev);
      return err;
    }
251 252 253

  for (i = 1; i < argc; i++)
    if (grub_strcmp (args[i], "help") == 0)
254 255 256 257 258
      {
	err = show_help (dev);
	grub_device_close (dev);
	return err;
      }
259

260
  parsed = (int *) grub_zalloc (argc * sizeof (int));
261 262 263 264 265 266 267

  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)
268
	  if (grub_strcmp (dev->disk->partition->partmap->name, cur->name) == 0)
269 270
	    {
	      for (curarg = cur->args; curarg->name; curarg++)
271
		if (grub_strncmp (curarg->name, args[i],
272
				  grub_strlen (curarg->name)) == 0
273 274
		    && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL
			 && (args[i][grub_strlen (curarg->name)] == '+'
275 276
			     || args[i][grub_strlen (curarg->name)] == '-'
			     || args[i][grub_strlen (curarg->name)] == 0))
277 278
			|| (curarg->type == GRUB_PARTTOOL_ARG_VAL
			    && args[i][grub_strlen (curarg->name)] == '=')))
279

280 281 282 283 284
		  break;
	      if (curarg->name)
		break;
	    }
	if (! cur)
285
	  {
286
	    grub_free (parsed);
287 288
	    grub_device_close (dev);
	    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unknown argument `%s'"),
289
			     args[i]);
290
	  }
291
	ptool = cur;
292
	pargs = (struct grub_parttool_args *)
293
	  grub_zalloc (ptool->nargs * sizeof (struct grub_parttool_args));
294
	for (j = i; j < argc; j++)
295
	  if (! parsed[j])
296 297
	    {
	      for (curarg = ptool->args; curarg->name; curarg++)
298
		if (grub_strncmp (curarg->name, args[j],
299
				   grub_strlen (curarg->name)) == 0
300 301
		    && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL
			 && (args[j][grub_strlen (curarg->name)] == '+'
302 303
			     || args[j][grub_strlen (curarg->name)] == '-'
			     || args[j][grub_strlen (curarg->name)] == 0))
304 305 306 307 308 309 310 311
			|| (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:
312
			pargs[curarg - ptool->args].bool
313 314 315 316
			  = (args[j][grub_strlen (curarg->name)] != '-');
			break;

		      case GRUB_PARTTOOL_ARG_VAL:
317
			pargs[curarg - ptool->args].str
318 319
			  = (args[j] + grub_strlen (curarg->name) + 1);
			break;
320

321 322 323 324 325 326 327 328 329 330 331 332
		      case GRUB_PARTTOOL_ARG_END:
			break;
		      }
		  }
	    }

	err = ptool->func (dev, pargs);
	grub_free (pargs);
	if (err)
	  break;
      }

333
  grub_free (parsed);
334 335 336 337 338 339 340 341 342
  grub_device_close (dev);
  return err;
}

static grub_command_t cmd;

GRUB_MOD_INIT(parttool)
{
  mymod = mod;
343
  cmd = grub_register_command ("parttool", grub_cmd_parttool,
344
			       N_("PARTITION COMMANDS"),
345
			       helpmsg);
346 347 348 349 350 351
}

GRUB_MOD_FINI(parttool)
{
  grub_unregister_command (cmd);
}