int r;
if (!strstr (err,
- "Error informing the kernel about modifications to partition"))
+ "Error informing the kernel about modifications to partition"))
return -1;
- r = command (NULL, NULL, "/sbin/blockdev", "--rereadpt", device, NULL);
+ r = command (NULL, NULL, "blockdev", "--rereadpt", device, NULL);
if (r == -1)
return -1;
return 0;
}
-#define RUN_PARTED(device,...) \
- do { \
- int r; \
- char *err; \
- \
- r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, \
- "/sbin/parted", "-s", "--", (device), __VA_ARGS__); \
- if (r == -1) { \
- if (recover_blkrrpart ((device), err) == -1) { \
- reply_with_error ("%s: parted: %s: %s", __func__, (device), err); \
- free (err); \
- return -1; \
- } \
- } \
- \
- free (err); \
+#define RUN_PARTED(error,device,...) \
+ do { \
+ int r; \
+ char *err; \
+ \
+ r = commandf (NULL, &err, COMMAND_FLAG_FOLD_STDOUT_ON_STDERR, \
+ "parted", "-s", "--", (device), __VA_ARGS__); \
+ if (r == -1) { \
+ if (recover_blkrrpart ((device), err) == -1) { \
+ reply_with_error ("%s: parted: %s: %s", __func__, (device), err); \
+ free (err); \
+ error; \
+ } \
+ } \
+ \
+ free (err); \
} while (0)
static const char *
check_parttype (const char *parttype)
{
/* Check and translate parttype. */
- if (strcmp (parttype, "aix") == 0 ||
- strcmp (parttype, "amiga") == 0 ||
- strcmp (parttype, "bsd") == 0 ||
- strcmp (parttype, "dasd") == 0 ||
- strcmp (parttype, "dvh") == 0 ||
- strcmp (parttype, "gpt") == 0 ||
- strcmp (parttype, "mac") == 0 ||
- strcmp (parttype, "msdos") == 0 ||
- strcmp (parttype, "pc98") == 0 ||
- strcmp (parttype, "sun") == 0)
+ if (STREQ (parttype, "aix") ||
+ STREQ (parttype, "amiga") ||
+ STREQ (parttype, "bsd") ||
+ STREQ (parttype, "dasd") ||
+ STREQ (parttype, "dvh") ||
+ STREQ (parttype, "gpt") ||
+ STREQ (parttype, "mac") ||
+ STREQ (parttype, "msdos") ||
+ STREQ (parttype, "pc98") ||
+ STREQ (parttype, "sun"))
return parttype;
- else if (strcmp (parttype, "rdb") == 0)
+ else if (STREQ (parttype, "rdb"))
return "amiga";
- else if (strcmp (parttype, "efi") == 0)
+ else if (STREQ (parttype, "efi"))
return "gpt";
- else if (strcmp (parttype, "mbr") == 0)
+ else if (STREQ (parttype, "mbr"))
return "msdos";
else
return NULL;
{
parttype = check_parttype (parttype);
if (!parttype) {
- reply_with_error ("part-init: unknown partition type: common choices are \"gpt\" and \"msdos\"");
+ reply_with_error ("unknown partition type: common choices are \"gpt\" and \"msdos\"");
return -1;
}
- RUN_PARTED (device, "mklabel", parttype, NULL);
+ RUN_PARTED (return -1, device, "mklabel", parttype, NULL);
udev_settle ();
char endstr[32];
/* Check and translate prlogex. */
- if (strcmp (prlogex, "primary") == 0 ||
- strcmp (prlogex, "logical") == 0 ||
- strcmp (prlogex, "extended") == 0)
+ if (STREQ (prlogex, "primary") ||
+ STREQ (prlogex, "logical") ||
+ STREQ (prlogex, "extended"))
;
- else if (strcmp (prlogex, "p") == 0)
+ else if (STREQ (prlogex, "p"))
prlogex = "primary";
- else if (strcmp (prlogex, "l") == 0)
+ else if (STREQ (prlogex, "l"))
prlogex = "logical";
- else if (strcmp (prlogex, "e") == 0)
+ else if (STREQ (prlogex, "e"))
prlogex = "extended";
else {
- reply_with_error ("part-add: unknown partition type: %s: this should be \"primary\", \"logical\" or \"extended\"", prlogex);
+ reply_with_error ("unknown partition type: %s: this should be \"primary\", \"logical\" or \"extended\"", prlogex);
return -1;
}
if (startsect < 0) {
- reply_with_error ("part-add: startsect cannot be negative");
+ reply_with_error ("startsect cannot be negative");
return -1;
}
/* but endsect can be negative */
* name_ to prlogex, eg. "primary". I would essentially describe
* this as a bug in the parted mkpart command.
*/
- RUN_PARTED (device, "mkpart", prlogex, startstr, endstr, NULL);
+ RUN_PARTED (return -1, device, "mkpart", prlogex, startstr, endstr, NULL);
udev_settle ();
}
int
+do_part_del (const char *device, int partnum)
+{
+ char partnum_str[16];
+ snprintf (partnum_str, sizeof partnum_str, "%d", partnum);
+
+ RUN_PARTED (return -1, device, "rm", partnum_str, NULL);
+
+ udev_settle ();
+ return 0;
+}
+
+int
do_part_disk (const char *device, const char *parttype)
{
const char *startstr;
parttype = check_parttype (parttype);
if (!parttype) {
- reply_with_error ("part-disk: unknown partition type: common choices are \"gpt\" and \"msdos\"");
+ reply_with_error ("unknown partition type: common choices are \"gpt\" and \"msdos\"");
return -1;
}
/* Voooooodooooooooo (thanks Jim Meyering for working this out). */
- if (strcmp (parttype, "msdos") == 0) {
+ if (STREQ (parttype, "msdos")) {
startstr = "1s";
endstr = "-1s";
- } else if (strcmp (parttype, "gpt") == 0) {
+ } else if (STREQ (parttype, "gpt")) {
startstr = "34s";
endstr = "-34s";
} else {
endstr = "-1s";
}
- RUN_PARTED (device,
- "mklabel", parttype,
- /* See comment about about the parted mkpart command. */
- "mkpart", strcmp (parttype, "gpt") == 0 ? "p1" : "primary",
- startstr, endstr, NULL);
+ RUN_PARTED (return -1,
+ device,
+ "mklabel", parttype,
+ /* See comment about about the parted mkpart command. */
+ "mkpart", STREQ (parttype, "gpt") ? "p1" : "primary",
+ startstr, endstr, NULL);
udev_settle ();
snprintf (partstr, sizeof partstr, "%d", partnum);
- RUN_PARTED (device, "set", partstr, "boot", bootable ? "on" : "off", NULL);
+ RUN_PARTED (return -1,
+ device, "set", partstr, "boot", bootable ? "on" : "off", NULL);
udev_settle ();
snprintf (partstr, sizeof partstr, "%d", partnum);
- RUN_PARTED (device, "name", partstr, name, NULL);
+ RUN_PARTED (return -1, device, "name", partstr, name, NULL);
udev_settle ();
return 0;
}
+/* Return the nth field from a string of ':'/';'-delimited strings.
+ * Useful for parsing the return value from print_partition_table
+ * function below.
+ */
+static char *
+get_table_field (const char *line, int n)
+{
+ const char *p = line;
+
+ while (*p && n > 0) {
+ p += strcspn (p, ":;") + 1;
+ n--;
+ }
+
+ if (n > 0) {
+ reply_with_error ("not enough fields in output of parted print command: %s",
+ line);
+ return NULL;
+ }
+
+ size_t len = strcspn (p, ":;");
+ char *q = strndup (p, len);
+ if (q == NULL) {
+ reply_with_perror ("strndup");
+ return NULL;
+ }
+
+ return q;
+}
+
static char **
print_partition_table (const char *device)
{
int r;
char **lines;
- r = command (&out, &err, "/sbin/parted", "-m", "--", device,
+ r = command (&out, &err, "parted", "-m", "--", device,
"unit", "b",
"print", NULL);
if (r == -1) {
if (!lines)
return NULL;
- if (lines[0] == NULL || strcmp (lines[0], "BYT;") != 0) {
- reply_with_error ("parted print: unknown signature, expected \"BYT;\" as first line of the output: %s",
+ if (lines[0] == NULL || STRNEQ (lines[0], "BYT;")) {
+ reply_with_error ("unknown signature, expected \"BYT;\" as first line of the output: %s",
lines[0] ? lines[0] : "(signature was null)");
free_strings (lines);
return NULL;
}
if (lines[1] == NULL) {
- reply_with_error ("parted print: parted didn't return a line describing the device");
+ reply_with_error ("parted didn't return a line describing the device");
free_strings (lines);
return NULL;
}
char *
do_part_get_parttype (const char *device)
{
- char **lines;
- char *r;
-
- lines = print_partition_table (device);
+ char **lines = print_partition_table (device);
if (!lines)
return NULL;
/* lines[1] is something like:
* "/dev/sda:1953525168s:scsi:512:512:msdos:ATA Hitachi HDT72101;"
*/
- if (strtok (lines[1], ":") == NULL /* device */
- || strtok (NULL, ":") == NULL /* size */
- || strtok (NULL, ":") == NULL /* transport */
- || strtok (NULL, ":") == NULL /* sector size */
- || strtok (NULL, ":") == NULL /* physical sector size */
- || (r = strtok (NULL, ":")) == NULL /* return value */
- ) {
- reply_with_error ("part_get_parttype: too few fields in output from parted print command: %s", lines[1]);
- free_strings (lines);
- return NULL;
- }
-
- r = strdup (r);
- if (!r) {
- reply_with_perror ("strdup");
+ char *r = get_table_field (lines[1], 5);
+ if (r == NULL) {
free_strings (lines);
return NULL;
}
&r->guestfs_int_partition_list_val[i].part_start,
&r->guestfs_int_partition_list_val[i].part_end,
&r->guestfs_int_partition_list_val[i].part_size) != 4) {
- reply_with_error ("part_list: could not parse row from output of parted print command: %s", lines[row]);
+ reply_with_error ("could not parse row from output of parted print command: %s", lines[row]);
goto error3;
}
}
free_strings (lines);
return NULL;
}
+
+int
+do_part_get_bootable (const char *device, int partnum)
+{
+ char **lines = print_partition_table (device);
+ if (!lines)
+ return -1;
+
+ /* We want lines[1+partnum]. */
+ if (count_strings (lines) < 1+partnum) {
+ reply_with_error ("partition number out of range: %d", partnum);
+ free_strings (lines);
+ return -1;
+ }
+
+ char *boot = get_table_field (lines[1+partnum], 6);
+ if (boot == NULL) {
+ free_strings (lines);
+ return -1;
+ }
+
+ int r = STREQ (boot, "boot");
+
+ free (boot);
+ free_strings (lines);
+
+ return r;
+}
+
+/* Currently we use sfdisk for getting and setting the ID byte. In
+ * future, extend parted to provide this functionality. As a result
+ * of using sfdisk, this won't work for non-MBR-style partitions, but
+ * that limitation is noted in the documentation and we can extend it
+ * later without breaking the ABI.
+ */
+int
+do_part_get_mbr_id (const char *device, int partnum)
+{
+ char partnum_str[16];
+ snprintf (partnum_str, sizeof partnum_str, "%d", partnum);
+
+ char *out, *err;
+ int r;
+
+ r = command (&out, &err, "sfdisk", "--print-id", device, partnum_str, NULL);
+ if (r == -1) {
+ reply_with_error ("sfdisk --print-id: %s", err);
+ free (out);
+ free (err);
+ return -1;
+ }
+
+ free (err);
+
+ /* It's printed in hex ... */
+ int id;
+ if (sscanf (out, "%x", &id) != 1) {
+ reply_with_error ("sfdisk --print-id: cannot parse output: %s", out);
+ free (out);
+ return -1;
+ }
+
+ free (out);
+ return id;
+}
+
+int
+do_part_set_mbr_id (const char *device, int partnum, int idbyte)
+{
+ char partnum_str[16];
+ snprintf (partnum_str, sizeof partnum_str, "%d", partnum);
+
+ char idbyte_str[16];
+ snprintf (idbyte_str, sizeof partnum_str, "%x", idbyte); /* NB: hex */
+
+ char *err;
+ int r;
+
+ r = command (NULL, &err, "sfdisk",
+ "--change-id", device, partnum_str, idbyte_str, NULL);
+ if (r == -1) {
+ reply_with_error ("sfdisk --change-id: %s", err);
+ free (err);
+ return -1;
+ }
+
+ free (err);
+ return 0;
+}