X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=daemon%2Fsfdisk.c;h=ec77465317b1afea57069740eede495560e2303f;hp=9d7a220f8a15802350295e0a511d74de57cb241d;hb=e44cf42f362d793c47d892a18a6853d88abd6ecb;hpb=5cd39c83e23eb300d1bdfa806902a31b409ff420 diff --git a/daemon/sfdisk.c b/daemon/sfdisk.c index 9d7a220..ec77465 100644 --- a/daemon/sfdisk.c +++ b/daemon/sfdisk.c @@ -1,5 +1,5 @@ /* libguestfs - the guestfsd daemon - * Copyright (C) 2009 Red Hat Inc. + * Copyright (C) 2009 Red Hat 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 @@ -31,15 +31,15 @@ static int sfdisk (const char *device, int n, int cyls, int heads, int sectors, - char * const* const lines) + const char *extra_flag, + char *const *lines) { FILE *fp; char buf[256]; int i; - IS_DEVICE (device, -1); + strcpy (buf, "sfdisk"); - strcpy (buf, "/sbin/sfdisk --no-reread"); if (n > 0) sprintf (buf + strlen (buf), " -N %d", n); if (cyls) @@ -48,46 +48,86 @@ sfdisk (const char *device, int n, int cyls, int heads, int sectors, sprintf (buf + strlen (buf), " -H %d", heads); if (sectors) sprintf (buf + strlen (buf), " -S %d", sectors); - /* Safe because of IS_DEVICE above: */ + + /* The above are all guaranteed to fit in the fixed-size buffer. + However, extra_flag and device have no restrictions, + so we must check. */ + + if (extra_flag) { + if (strlen (buf) + 1 + strlen (extra_flag) >= sizeof buf) { + reply_with_error ("internal buffer overflow: sfdisk extra_flag too long"); + return -1; + } + sprintf (buf + strlen (buf), " %s", extra_flag); + } + + if (strlen (buf) + 1 + strlen (device) >= sizeof buf) { + reply_with_error ("internal buffer overflow: sfdisk device name too long"); + return -1; + } sprintf (buf + strlen (buf), " %s", device); + if (verbose) + printf ("%s\n", buf); + fp = popen (buf, "w"); if (fp == NULL) { - reply_with_perror (buf); + reply_with_perror ("failed to open pipe: %s", buf); return -1; } for (i = 0; lines[i] != NULL; ++i) { if (fprintf (fp, "%s\n", lines[i]) < 0) { - reply_with_perror (buf); - fclose (fp); + reply_with_perror ("failed to write to pipe: %s", buf); + pclose (fp); return -1; } } - if (fclose (fp) == EOF) { - reply_with_perror (buf); - fclose (fp); + if (pclose (fp) != 0) { + reply_with_error ("%s: external command failed", buf); return -1; } + /* sfdisk sometimes fails on fast machines with: + * + * Re-reading the partition table ... + * BLKRRPART: Device or resource busy + * The command to re-read the partition table failed. + * Run partprobe(8), kpartx(8) or reboot your system now, + * before using mkfs + * + * Unclear if this is a bug in sfdisk or the kernel or some + * other component. In any case, reread the partition table + * unconditionally here. + */ + (void) command (NULL, NULL, "blockdev", "--rereadpt", NULL); + + udev_settle (); + return 0; } int do_sfdisk (const char *device, int cyls, int heads, int sectors, - char * const* const lines) + char *const *lines) { - return sfdisk (device, 0, cyls, heads, sectors, lines); + return sfdisk (device, 0, cyls, heads, sectors, NULL, lines); } int do_sfdisk_N (const char *device, int n, int cyls, int heads, int sectors, - const char *line) + const char *line) { - const char *lines[2] = { line, NULL }; + char const *const lines[2] = { line, NULL }; + + return sfdisk (device, n, cyls, heads, sectors, NULL, (void *) lines); +} - return sfdisk (device, n, cyls, heads, sectors, lines); +int +do_sfdiskM (const char *device, char *const *lines) +{ + return sfdisk (device, 0, 0, 0, 0, "-uM", lines); } static char * @@ -96,11 +136,9 @@ sfdisk_flag (const char *device, const char *flag) char *out, *err; int r; - IS_DEVICE (device, NULL); - - r = command (&out, &err, "/sbin/sfdisk", flag, device, NULL); + r = command (&out, &err, "sfdisk", flag, device, NULL); if (r == -1) { - reply_with_error ("sfdisk: %s: %s", device, err); + reply_with_error ("%s: %s", device, err); free (out); free (err); return NULL; @@ -108,6 +146,8 @@ sfdisk_flag (const char *device, const char *flag) free (err); + udev_settle (); + return out; /* caller frees */ }