]>
Commit | Line | Data |
---|---|---|
ea761d40 | 1 | /* parttool.c - common dispatcher and parser for partition operations */ |
2 | /* | |
3 | * GRUB -- GRand Unified Bootloader | |
4 | * Copyright (C) 2009 Free Software Foundation, Inc. | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
19 | */ | |
20 | ||
21 | #include <grub/types.h> | |
22 | #include <grub/misc.h> | |
23 | #include <grub/mm.h> | |
24 | #include <grub/err.h> | |
25 | #include <grub/dl.h> | |
26 | #include <grub/normal.h> | |
27 | #include <grub/device.h> | |
28 | #include <grub/disk.h> | |
29 | #include <grub/partition.h> | |
30 | #include <grub/parttool.h> | |
31 | #include <grub/command.h> | |
77a79592 | 32 | #include <grub/i18n.h> |
ea761d40 | 33 | |
e745cf0c VS |
34 | GRUB_MOD_LICENSE ("GPLv2+"); |
35 | ||
ea761d40 | 36 | static struct grub_parttool *parts = 0; |
37 | static int curhandle = 0; | |
38 | static grub_dl_t mymod; | |
e4343593 | 39 | static char helpmsg[] = |
6e0632e2 | 40 | N_("Perform COMMANDS on partition.\n" |
805a8dcc | 41 | "Use `parttool PARTITION help' for the list " |
6e0632e2 | 42 | "of available commands."); |
ea761d40 | 43 | |
b39f9d20 | 44 | int |
45 | grub_parttool_register(const char *part_name, | |
ea761d40 | 46 | const grub_parttool_function_t func, |
47 | const struct grub_parttool_argdesc *args) | |
48 | { | |
49 | struct grub_parttool *cur; | |
50 | int nargs = 0; | |
51 | ||
ea761d40 | 52 | if (! parts) |
53 | grub_dl_ref (mymod); | |
ea761d40 | 54 | |
55 | cur = (struct grub_parttool *) grub_malloc (sizeof (struct grub_parttool)); | |
56 | cur->next = parts; | |
57 | cur->name = grub_strdup (part_name); | |
58 | cur->handle = curhandle++; | |
59 | for (nargs = 0; args[nargs].name != 0; nargs++); | |
60 | cur->nargs = nargs; | |
b39f9d20 | 61 | cur->args = (struct grub_parttool_argdesc *) |
f725fa7c PJ |
62 | grub_calloc (nargs + 1, sizeof (struct grub_parttool_argdesc)); |
63 | if (!cur->args) | |
64 | { | |
65 | grub_free (cur); | |
66 | curhandle--; | |
67 | return -1; | |
68 | } | |
b39f9d20 | 69 | grub_memcpy (cur->args, args, |
ea761d40 | 70 | (nargs + 1) * sizeof (struct grub_parttool_argdesc)); |
b39f9d20 | 71 | |
ea761d40 | 72 | cur->func = func; |
73 | parts = cur; | |
74 | return cur->handle; | |
75 | } | |
76 | ||
77 | void | |
78 | grub_parttool_unregister (int handle) | |
79 | { | |
80 | struct grub_parttool *prev = 0, *cur, *t; | |
81 | for (cur = parts; cur; ) | |
82 | if (cur->handle == handle) | |
83 | { | |
84 | grub_free (cur->args); | |
85 | grub_free (cur->name); | |
86 | if (prev) | |
87 | prev->next = cur->next; | |
88 | else | |
89 | parts = cur->next; | |
90 | t = cur; | |
91 | cur = cur->next; | |
92 | grub_free (t); | |
93 | } | |
94 | else | |
95 | { | |
96 | prev = cur; | |
97 | cur = cur->next; | |
98 | } | |
ea761d40 | 99 | if (! parts) |
100 | grub_dl_unref (mymod); | |
ea761d40 | 101 | } |
102 | ||
5aec2afe VS |
103 | static grub_err_t |
104 | show_help (grub_device_t dev) | |
105 | { | |
106 | int found = 0; | |
107 | struct grub_parttool *cur; | |
108 | ||
109 | for (cur = parts; cur; cur = cur->next) | |
110 | if (grub_strcmp (dev->disk->partition->partmap->name, cur->name) == 0) | |
111 | { | |
112 | struct grub_parttool_argdesc *curarg; | |
113 | found = 1; | |
114 | for (curarg = cur->args; curarg->name; curarg++) | |
115 | { | |
116 | int spacing = 20; | |
117 | ||
118 | spacing -= grub_strlen (curarg->name); | |
119 | grub_printf ("%s", curarg->name); | |
120 | ||
121 | switch (curarg->type) | |
122 | { | |
123 | case GRUB_PARTTOOL_ARG_BOOL: | |
124 | grub_printf ("+/-"); | |
125 | spacing -= 3; | |
126 | break; | |
127 | ||
128 | case GRUB_PARTTOOL_ARG_VAL: | |
129 | grub_xputs (_("=VAL")); | |
130 | spacing -= 4; | |
131 | break; | |
132 | ||
133 | case GRUB_PARTTOOL_ARG_END: | |
134 | break; | |
135 | } | |
136 | while (spacing-- > 0) | |
137 | grub_printf (" "); | |
138 | grub_puts_ (curarg->desc); | |
139 | } | |
140 | } | |
141 | if (! found) | |
16f7455b | 142 | grub_printf_ (N_("Sorry, no parttool is available for %s\n"), |
5aec2afe VS |
143 | dev->disk->partition->partmap->name); |
144 | return GRUB_ERR_NONE; | |
145 | } | |
146 | ||
ea761d40 | 147 | static grub_err_t |
148 | grub_cmd_parttool (grub_command_t cmd __attribute__ ((unused)), | |
149 | int argc, char **args) | |
150 | { | |
151 | grub_device_t dev; | |
152 | struct grub_parttool *cur, *ptool; | |
153 | int *parsed; | |
154 | int i, j; | |
155 | grub_err_t err = GRUB_ERR_NONE; | |
156 | ||
e4343593 | 157 | if (argc < 1) |
158 | { | |
6e0632e2 | 159 | grub_puts_ (helpmsg); |
e4343593 | 160 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "too few arguments"); |
161 | } | |
ea761d40 | 162 | |
163 | if (args[0][0] == '(' && args[0][grub_strlen (args[0]) - 1] == ')') | |
164 | { | |
165 | args[0][grub_strlen (args[0]) - 1] = 0; | |
b39f9d20 | 166 | dev = grub_device_open (args[0] + 1); |
ea761d40 | 167 | args[0][grub_strlen (args[0]) - 1] = ')'; |
168 | } | |
169 | else | |
b39f9d20 | 170 | dev = grub_device_open (args[0]); |
ea761d40 | 171 | |
172 | if (! dev) | |
173 | return grub_errno; | |
174 | ||
175 | if (! dev->disk) | |
176 | { | |
177 | grub_device_close (dev); | |
178 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a disk"); | |
179 | } | |
180 | ||
181 | if (! dev->disk->partition) | |
182 | { | |
183 | grub_device_close (dev); | |
184 | return grub_error (GRUB_ERR_BAD_ARGUMENT, "not a partition"); | |
185 | } | |
186 | ||
e4343593 | 187 | /* Load modules. */ |
a6393224 | 188 | if (! grub_no_modules) |
e4343593 | 189 | { |
190 | const char *prefix; | |
191 | prefix = grub_env_get ("prefix"); | |
192 | if (prefix) | |
ea761d40 | 193 | { |
e4343593 | 194 | char *filename; |
ea761d40 | 195 | |
92cd0f6e VS |
196 | filename = grub_xasprintf ("%s/" GRUB_TARGET_CPU "-" GRUB_PLATFORM |
197 | "/parttool.lst", prefix); | |
e4343593 | 198 | if (filename) |
199 | { | |
200 | grub_file_t file; | |
b39f9d20 | 201 | |
ca0a4f68 | 202 | file = grub_file_open (filename, GRUB_FILE_TYPE_GRUB_MODULE_LIST); |
e4343593 | 203 | if (file) |
204 | { | |
205 | char *buf = 0; | |
206 | for (;; grub_free(buf)) | |
207 | { | |
208 | char *p, *name; | |
ea761d40 | 209 | |
e4343593 | 210 | buf = grub_file_getline (file); |
b39f9d20 | 211 | |
e4343593 | 212 | if (! buf) |
ea761d40 | 213 | break; |
b39f9d20 | 214 | |
e4343593 | 215 | name = buf; |
9fdb2d7b VS |
216 | while (grub_isspace (name[0])) |
217 | name++; | |
ea761d40 | 218 | |
e4343593 | 219 | if (! grub_isgraph (name[0])) |
220 | continue; | |
b39f9d20 | 221 | |
e4343593 | 222 | p = grub_strchr (name, ':'); |
223 | if (! p) | |
224 | continue; | |
b39f9d20 | 225 | |
e4343593 | 226 | *p = '\0'; |
9fdb2d7b VS |
227 | p++; |
228 | while (*p == ' ' || *p == '\t') | |
229 | p++; | |
e4343593 | 230 | |
231 | if (! grub_isgraph (*p)) | |
232 | continue; | |
b39f9d20 | 233 | |
e4343593 | 234 | if (grub_strcmp (name, dev->disk->partition->partmap->name) |
235 | != 0) | |
236 | continue; | |
b39f9d20 | 237 | |
e4343593 | 238 | grub_dl_load (p); |
239 | } | |
b39f9d20 | 240 | |
e4343593 | 241 | grub_file_close (file); |
242 | } | |
b39f9d20 | 243 | |
e4343593 | 244 | grub_free (filename); |
245 | } | |
ea761d40 | 246 | } |
e4343593 | 247 | /* Ignore errors. */ |
248 | grub_errno = GRUB_ERR_NONE; | |
249 | } | |
e4343593 | 250 | |
251 | if (argc == 1) | |
4947f11b VS |
252 | { |
253 | err = show_help (dev); | |
254 | grub_device_close (dev); | |
255 | return err; | |
256 | } | |
e4343593 | 257 | |
258 | for (i = 1; i < argc; i++) | |
259 | if (grub_strcmp (args[i], "help") == 0) | |
4947f11b VS |
260 | { |
261 | err = show_help (dev); | |
262 | grub_device_close (dev); | |
263 | return err; | |
264 | } | |
e4343593 | 265 | |
f725fa7c | 266 | parsed = (int *) grub_calloc (argc, sizeof (int)); |
ea761d40 | 267 | |
268 | for (i = 1; i < argc; i++) | |
269 | if (! parsed[i]) | |
270 | { | |
271 | struct grub_parttool_argdesc *curarg; | |
272 | struct grub_parttool_args *pargs; | |
273 | for (cur = parts; cur; cur = cur->next) | |
e4343593 | 274 | if (grub_strcmp (dev->disk->partition->partmap->name, cur->name) == 0) |
ea761d40 | 275 | { |
276 | for (curarg = cur->args; curarg->name; curarg++) | |
b39f9d20 | 277 | if (grub_strncmp (curarg->name, args[i], |
e4343593 | 278 | grub_strlen (curarg->name)) == 0 |
b39f9d20 | 279 | && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL |
280 | && (args[i][grub_strlen (curarg->name)] == '+' | |
e4343593 | 281 | || args[i][grub_strlen (curarg->name)] == '-' |
282 | || args[i][grub_strlen (curarg->name)] == 0)) | |
ea761d40 | 283 | || (curarg->type == GRUB_PARTTOOL_ARG_VAL |
284 | && args[i][grub_strlen (curarg->name)] == '='))) | |
b39f9d20 | 285 | |
ea761d40 | 286 | break; |
287 | if (curarg->name) | |
288 | break; | |
289 | } | |
290 | if (! cur) | |
3db4f05a | 291 | { |
5db2190f | 292 | grub_free (parsed); |
3db4f05a AB |
293 | grub_device_close (dev); |
294 | return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("unknown argument `%s'"), | |
ea761d40 | 295 | args[i]); |
3db4f05a | 296 | } |
ea761d40 | 297 | ptool = cur; |
b39f9d20 | 298 | pargs = (struct grub_parttool_args *) |
f725fa7c | 299 | grub_calloc (ptool->nargs, sizeof (struct grub_parttool_args)); |
ea761d40 | 300 | for (j = i; j < argc; j++) |
e4343593 | 301 | if (! parsed[j]) |
ea761d40 | 302 | { |
303 | for (curarg = ptool->args; curarg->name; curarg++) | |
35139e8a | 304 | if (grub_strncmp (curarg->name, args[j], |
e4343593 | 305 | grub_strlen (curarg->name)) == 0 |
b39f9d20 | 306 | && ((curarg->type == GRUB_PARTTOOL_ARG_BOOL |
307 | && (args[j][grub_strlen (curarg->name)] == '+' | |
e4343593 | 308 | || args[j][grub_strlen (curarg->name)] == '-' |
309 | || args[j][grub_strlen (curarg->name)] == 0)) | |
ea761d40 | 310 | || (curarg->type == GRUB_PARTTOOL_ARG_VAL |
311 | && args[j][grub_strlen (curarg->name)] == '='))) | |
312 | { | |
313 | parsed[j] = 1; | |
314 | pargs[curarg - ptool->args].set = 1; | |
315 | switch (curarg->type) | |
316 | { | |
317 | case GRUB_PARTTOOL_ARG_BOOL: | |
b39f9d20 | 318 | pargs[curarg - ptool->args].bool |
ea761d40 | 319 | = (args[j][grub_strlen (curarg->name)] != '-'); |
320 | break; | |
321 | ||
322 | case GRUB_PARTTOOL_ARG_VAL: | |
b39f9d20 | 323 | pargs[curarg - ptool->args].str |
ea761d40 | 324 | = (args[j] + grub_strlen (curarg->name) + 1); |
325 | break; | |
b39f9d20 | 326 | |
ea761d40 | 327 | case GRUB_PARTTOOL_ARG_END: |
328 | break; | |
329 | } | |
330 | } | |
331 | } | |
332 | ||
333 | err = ptool->func (dev, pargs); | |
334 | grub_free (pargs); | |
335 | if (err) | |
336 | break; | |
337 | } | |
338 | ||
e4343593 | 339 | grub_free (parsed); |
ea761d40 | 340 | grub_device_close (dev); |
341 | return err; | |
342 | } | |
343 | ||
344 | static grub_command_t cmd; | |
345 | ||
346 | GRUB_MOD_INIT(parttool) | |
347 | { | |
ea761d40 | 348 | mymod = mod; |
b39f9d20 | 349 | cmd = grub_register_command ("parttool", grub_cmd_parttool, |
77a79592 | 350 | N_("PARTITION COMMANDS"), |
e4343593 | 351 | helpmsg); |
ea761d40 | 352 | } |
353 | ||
354 | GRUB_MOD_FINI(parttool) | |
355 | { | |
356 | grub_unregister_command (cmd); | |
357 | } |