Implement "force" (-F) option for gpart destroy verb.

This option doesn't passed to kernel and handled in user-space.
With -F option gpart creates new "delete" request for each
partition in table. Each request has flags="X" that disables
auto-commit feature. Last request is the original "destroy" request.
It has own flags and can have disabled or enabled auto-commit feature.
If error is occurred when deleting partitions, then new "undo" request
is created and all changes will be rolled back.

Approved by:	kib (mentor)
This commit is contained in:
Andrey V. Elsukov 2010-09-24 08:40:43 +00:00
parent 93ea4a71bf
commit 6305a96c20
2 changed files with 106 additions and 15 deletions

View File

@ -67,6 +67,7 @@ static char ssize[32];
#define GPART_PARAM_BOOTCODE "bootcode"
#define GPART_PARAM_INDEX "index"
#define GPART_PARAM_PARTCODE "partcode"
#define GPART_PARAM_FORCE "force"
static struct gclass *find_class(struct gmesh *, const char *);
static struct ggeom * find_geom(struct gclass *, const char *);
@ -84,6 +85,8 @@ static void gpart_show_geom(struct ggeom *, const char *);
static int gpart_show_hasopt(struct gctl_req *, const char *, const char *);
static void gpart_write_partcode(struct ggeom *, int, void *, ssize_t);
static void gpart_write_partcode_vtoc8(struct ggeom *, int, void *);
static void gpart_destroy(struct gctl_req *, unsigned int);
static void gpart_print_error(const char *);
struct g_command PUBSYM(class_commands)[] = {
{ "add", 0, gpart_issue, {
@ -120,10 +123,11 @@ struct g_command PUBSYM(class_commands)[] = {
G_OPT_SENTINEL },
"-i index [-f flags] geom"
},
{ "destroy", 0, gpart_issue, {
{ "destroy", 0, gpart_destroy, {
{ 'F', GPART_PARAM_FORCE, NULL, G_TYPE_BOOL },
{ 'f', "flags", GPART_FLAGS, G_TYPE_STRING },
G_OPT_SENTINEL },
"[-f flags] geom"
"[-F] [-f flags] geom"
},
{ "modify", 0, gpart_issue, {
{ 'i', GPART_PARAM_INDEX, NULL, G_TYPE_NUMBER },
@ -853,11 +857,105 @@ gpart_bootcode(struct gctl_req *req, unsigned int fl)
geom_deletetree(&mesh);
}
static void
gpart_destroy(struct gctl_req *req, unsigned int fl)
{
struct gmesh mesh;
struct gclass *classp;
struct gctl_req *req2;
struct ggeom *gp;
struct gprovider *pp;
const char *s;
int error, val;
intmax_t idx;
if (gctl_has_param(req, GPART_PARAM_FORCE)) {
val = gctl_get_int(req, GPART_PARAM_FORCE);
error = gctl_delete_param(req, GPART_PARAM_FORCE);
if (error)
errc(EXIT_FAILURE, error, "internal error");
if (val == 0)
goto done;
s = gctl_get_ascii(req, "class");
if (s == NULL)
abort();
error = geom_gettree(&mesh);
if (error != 0)
errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
classp = find_class(&mesh, s);
if (classp == NULL) {
geom_deletetree(&mesh);
errx(EXIT_FAILURE, "Class %s not found.", s);
}
s = gctl_get_ascii(req, "arg0");
if (s == NULL)
abort();
gp = find_geom(classp, s);
if (gp == NULL)
errx(EXIT_FAILURE, "No such geom: %s.", s);
val = 0;
LIST_FOREACH(pp, &gp->lg_provider, lg_provider){
s = find_provcfg(pp, "index");
if (s == NULL)
errx(EXIT_FAILURE, "Index not found for %s.",
pp->lg_name);
idx = strtoimax(s, NULL, 0);
req2 = gctl_get_handle();
gctl_ro_param(req2, "class", -1, classp->lg_name);
gctl_ro_param(req2, "arg0", -1, gp->lg_name);
gctl_ro_param(req2, "verb", -1, "delete");
gctl_ro_param(req2, GPART_PARAM_INDEX,
sizeof(intmax_t), &idx);
gctl_ro_param(req2, "flags", -1, "X");
s = gctl_issue(req2);
if (s != NULL && s[0] != '\0') {
gpart_print_error(s);
gctl_free(req2);
if (val) { /* try to undo changes */
req2 = gctl_get_handle();
gctl_ro_param(req2, "verb", -1,
"undo");
gctl_ro_param(req2, "class", -1,
classp->lg_name);
gctl_ro_param(req2, "arg0", -1,
gp->lg_name);
gctl_issue(req2);
gctl_free(req2);
}
geom_deletetree(&mesh);
exit(EXIT_FAILURE);
}
gctl_free(req2);
val = 1;
}
geom_deletetree(&mesh);
}
done:
gpart_issue(req, fl);
}
static void
gpart_print_error(const char *errstr)
{
char *errmsg;
int error;
error = strtol(errstr, &errmsg, 0);
if (errmsg != errstr) {
while (errmsg[0] == ' ')
errmsg++;
if (errmsg[0] != '\0')
warnc(error, "%s", errmsg);
else
warnc(error, NULL);
} else
warnx("%s", errmsg);
}
static void
gpart_issue(struct gctl_req *req, unsigned int fl __unused)
{
char buf[4096];
char *errmsg;
const char *errstr;
int error, status;
@ -883,17 +981,7 @@ gpart_issue(struct gctl_req *req, unsigned int fl __unused)
goto done;
}
error = strtol(errstr, &errmsg, 0);
if (errmsg != errstr) {
while (errmsg[0] == ' ')
errmsg++;
if (errmsg[0] != '\0')
warnc(error, "%s", errmsg);
else
warnc(error, NULL);
} else
warnx("%s", errmsg);
gpart_print_error(errstr);
status = EXIT_FAILURE;
done:

View File

@ -24,7 +24,7 @@
.\"
.\" $FreeBSD$
.\"
.Dd July 27, 2010
.Dd Sep 24, 2010
.Dt GPART 8
.Os
.Sh NAME
@ -118,6 +118,7 @@ utility:
.\" ==== DESTROY ====
.Nm
.Cm destroy
.Op Fl F
.Op Fl f Ar flags
.Ar geom
.\" ==== MODIFY ====
@ -317,6 +318,8 @@ Destroy the partitioning scheme as implemented by geom
.Pp
Additional options include:
.Bl -tag -width 10n
.It Fl F
Forced destroying of the partition table even if it is not empty.
.It Fl f Ar flags
Additional operational flags.
See the section entitled