summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/pt-mbr.h1
-rw-r--r--libfdisk/docs/libfdisk-sections.txt6
-rw-r--r--libfdisk/src/context.c33
-rw-r--r--libfdisk/src/dos.c5
-rw-r--r--libfdisk/src/fdiskP.h4
-rw-r--r--libfdisk/src/gpt.c6
-rw-r--r--libfdisk/src/libfdisk.h.in2
-rw-r--r--libfdisk/src/libfdisk.sym2
-rw-r--r--libfdisk/src/sgi.c2
-rw-r--r--libfdisk/src/sun.c2
-rw-r--r--libfdisk/src/utils.c73
11 files changed, 106 insertions, 30 deletions
diff --git a/include/pt-mbr.h b/include/pt-mbr.h
index fab65ea07..8c4f8e6a8 100644
--- a/include/pt-mbr.h
+++ b/include/pt-mbr.h
@@ -11,6 +11,7 @@ struct dos_partition {
} __attribute__((packed));
#define MBR_PT_OFFSET 0x1be
+#define MBR_PT_BOOTBITS_SIZE 440
static inline struct dos_partition *mbr_get_partition(unsigned char *mbr, int i)
{
diff --git a/libfdisk/docs/libfdisk-sections.txt b/libfdisk/docs/libfdisk-sections.txt
index 8713d23b3..339c15cd3 100644
--- a/libfdisk/docs/libfdisk-sections.txt
+++ b/libfdisk/docs/libfdisk-sections.txt
@@ -282,6 +282,7 @@ fdisk_unref_table
fdisk_context
fdisk_assign_device
fdisk_deassign_device
+fdisk_enable_bootbits_protection
fdisk_enable_details
fdisk_enable_listonly
fdisk_get_alignment_offset
@@ -300,22 +301,23 @@ fdisk_get_parent
fdisk_get_physector_size
fdisk_get_sector_size
fdisk_get_size_unit
-FDISK_PLURAL
-FDISK_SINGULAR
fdisk_get_unit
fdisk_get_units_per_sector
fdisk_has_label
+fdisk_has_protected_bootbits
fdisk_is_details
fdisk_is_labeltype
fdisk_is_listonly
fdisk_is_readonly
fdisk_new_context
fdisk_new_nested_context
+FDISK_PLURAL
fdisk_ref_context
fdisk_set_first_lba
fdisk_set_last_lba
fdisk_set_size_unit
fdisk_set_unit
+FDISK_SINGULAR
fdisk_unref_context
fdisk_use_cylinders
</SECTION>
diff --git a/libfdisk/src/context.c b/libfdisk/src/context.c
index 84867b0ab..efc961cf7 100644
--- a/libfdisk/src/context.c
+++ b/libfdisk/src/context.c
@@ -94,12 +94,13 @@ static int init_nested_from_parent(struct fdisk_context *cxt, int isnew)
cxt->user_log_sector = parent->user_log_sector;
cxt->user_pyh_sector = parent->user_pyh_sector;
- /* parent <--> nested independent setting, initialize for new nested
+ /* parent <--> nested independent setting, initialize for new nested
* contexts only */
if (isnew) {
cxt->listonly = parent->listonly;
cxt->display_details = parent->display_details;
cxt->display_in_cyl_units = parent->display_in_cyl_units;
+ cxt->protect_bootbits = parent->protect_bootbits;
}
free(cxt->dev_path);
@@ -304,6 +305,36 @@ int fdisk_has_label(struct fdisk_context *cxt)
}
/**
+ * fdisk_has_protected_bootbits:
+ * @cxt: fdisk context
+ *
+ * Returns: return 1 if boot bits protection enabled.
+ */
+int fdisk_has_protected_bootbits(struct fdisk_context *cxt)
+{
+ return cxt && cxt->protect_bootbits;
+}
+
+/**
+ * fdisk_enable_bootbits_protection:
+ * @cxt: fdisk context
+ * @enable: 1 or 0
+ *
+ * The library zeroizes all the first sector when create a new disk label by
+ * default. This function allows to control this behavior. For now it's
+ * supported for MBR and GPT.
+ *
+ * Returns: 0 on success, < 0 on error.
+ */
+int fdisk_enable_bootbits_protection(struct fdisk_context *cxt, int enable)
+{
+ if (!cxt)
+ return -EINVAL;
+ cxt->protect_bootbits = enable ? 1 : 0;
+ return 0;
+}
+
+/**
* fdisk_get_npartitions:
* @cxt: context
*
diff --git a/libfdisk/src/dos.c b/libfdisk/src/dos.c
index 6468071ff..f2308e3e0 100644
--- a/libfdisk/src/dos.c
+++ b/libfdisk/src/dos.c
@@ -659,7 +659,10 @@ static int dos_create_disklabel(struct fdisk_context *cxt)
if (!has_id)
random_get_bytes(&id, sizeof(id));
- rc = fdisk_init_firstsector_buffer(cxt);
+ if (fdisk_has_protected_bootbits(cxt))
+ rc = fdisk_init_firstsector_buffer(cxt, 0, MBR_PT_BOOTBITS_SIZE);
+ else
+ rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
if (rc)
return rc;
dos_init(cxt);
diff --git a/libfdisk/src/fdiskP.h b/libfdisk/src/fdiskP.h
index dc561f389..0ca498d54 100644
--- a/libfdisk/src/fdiskP.h
+++ b/libfdisk/src/fdiskP.h
@@ -350,6 +350,7 @@ struct fdisk_context {
unsigned int readonly : 1, /* don't write to the device */
display_in_cyl_units : 1, /* for obscure labels */
display_details : 1, /* expert display mode */
+ protect_bootbits : 1, /* don't zeroize fll irst sector */
listonly : 1; /* list partition, nothing else */
int sizeunit; /* SIZE fields, FDISK_SIZEUNIT_* */
@@ -402,7 +403,8 @@ extern int fdisk_apply_user_device_properties(struct fdisk_context *cxt);
extern void fdisk_zeroize_device_properties(struct fdisk_context *cxt);
/* utils.c */
-extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt);
+extern int fdisk_init_firstsector_buffer(struct fdisk_context *cxt,
+ unsigned int protect_off, unsigned int protect_size);
extern int fdisk_read_firstsector(struct fdisk_context *cxt);
extern char *fdisk_partname(const char *dev, size_t partno);
diff --git a/libfdisk/src/gpt.c b/libfdisk/src/gpt.c
index 9ceb01a6e..62271c115 100644
--- a/libfdisk/src/gpt.c
+++ b/libfdisk/src/gpt.c
@@ -27,6 +27,7 @@
#include "bitops.h"
#include "strutils.h"
#include "all-io.h"
+#include "pt-mbr.h"
/**
* SECTION: gpt
@@ -406,7 +407,10 @@ static int gpt_mknew_pmbr(struct fdisk_context *cxt)
if (!cxt || !cxt->firstsector)
return -ENOSYS;
- rc = fdisk_init_firstsector_buffer(cxt);
+ if (fdisk_has_protected_bootbits(cxt))
+ rc = fdisk_init_firstsector_buffer(cxt, 0, MBR_PT_BOOTBITS_SIZE);
+ else
+ rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
if (rc)
return rc;
diff --git a/libfdisk/src/libfdisk.h.in b/libfdisk/src/libfdisk.h.in
index a38ef47c9..5a14c26f1 100644
--- a/libfdisk/src/libfdisk.h.in
+++ b/libfdisk/src/libfdisk.h.in
@@ -211,6 +211,8 @@ enum {
int fdisk_set_size_unit(struct fdisk_context *cxt, int unit);
int fdisk_get_size_unit(struct fdisk_context *cxt);
+int fdisk_has_protected_bootbits(struct fdisk_context *cxt);
+int fdisk_enable_bootbits_protection(struct fdisk_context *cxt, int enable);
/* parttype.c */
struct fdisk_parttype *fdisk_new_parttype(void);
diff --git a/libfdisk/src/libfdisk.sym b/libfdisk/src/libfdisk.sym
index 5ff270b59..4d8276eca 100644
--- a/libfdisk/src/libfdisk.sym
+++ b/libfdisk/src/libfdisk.sym
@@ -244,4 +244,6 @@ FDISK_2.27 {
fdisk_script_set_fgets;
fdisk_script_set_userdata;
fdisk_script_get_userdata;
+ fdisk_enable_bootbits_protection;
+ fdisk_has_protected_bootbits;
} FDISK_2.26;
diff --git a/libfdisk/src/sgi.c b/libfdisk/src/sgi.c
index cd4cedff0..7cc68b501 100644
--- a/libfdisk/src/sgi.c
+++ b/libfdisk/src/sgi.c
@@ -965,7 +965,7 @@ static int sgi_create_disklabel(struct fdisk_context *cxt)
}
}
#endif
- rc = fdisk_init_firstsector_buffer(cxt);
+ rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
if (rc)
return rc;
diff --git a/libfdisk/src/sun.c b/libfdisk/src/sun.c
index d99c39f6f..27e3bdd00 100644
--- a/libfdisk/src/sun.c
+++ b/libfdisk/src/sun.c
@@ -209,7 +209,7 @@ static int sun_create_disklabel(struct fdisk_context *cxt)
assert(fdisk_is_label(cxt, SUN));
/* map first sector to header */
- rc = fdisk_init_firstsector_buffer(cxt);
+ rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
if (rc)
return rc;
diff --git a/libfdisk/src/utils.c b/libfdisk/src/utils.c
index 482a3062d..cc470d99b 100644
--- a/libfdisk/src/utils.c
+++ b/libfdisk/src/utils.c
@@ -10,14 +10,49 @@
* @short_description: misc fdisk functions
*/
+static int read_from_device(struct fdisk_context *cxt,
+ unsigned char *buf,
+ uintmax_t start, size_t size)
+{
+ ssize_t r;
+
+ assert(cxt);
+
+ DBG(CXT, ul_debugobj(cxt, "reading: offset=%ju, size=%zu",
+ start, size));
+
+ r = lseek(cxt->dev_fd, start, SEEK_SET);
+ if (r == -1)
+ {
+ DBG(CXT, ul_debugobj(cxt, "failed to seek to offset %ju: %m", start));
+ return -errno;
+ }
+
+ r = read(cxt->dev_fd, buf, size);
+ if (r < 0 || r != size) {
+ if (!errno)
+ errno = EINVAL; /* probably too small file/device */
+ DBG(CXT, ul_debugobj(cxt, "failed to read %zu from offset %ju: %m",
+ size, start));
+ return -errno;
+ }
+
+ return 0;
+}
+
+
/*
* Zeros in-memory first sector buffer
*/
-int fdisk_init_firstsector_buffer(struct fdisk_context *cxt)
+int fdisk_init_firstsector_buffer(struct fdisk_context *cxt,
+ unsigned int protect_off,
+ unsigned int protect_size)
{
if (!cxt)
return -EINVAL;
+ assert(protect_off + protect_size <= cxt->sector_size);
+
if (!cxt->firstsector || cxt->firstsector_bufsz != cxt->sector_size) {
/* Let's allocate a new buffer if no allocated yet, or the
* current buffer has incorrect size */
@@ -36,43 +71,37 @@ int fdisk_init_firstsector_buffer(struct fdisk_context *cxt)
DBG(CXT, ul_debugobj(cxt, "zeroize in-memory first sector buffer"));
memset(cxt->firstsector, 0, cxt->firstsector_bufsz);
+
+ if (protect_size) {
+ /*
+ * It would be possible to reuse data from cxt->firstsector
+ * (call memset() for non-protected area only) and avoid one
+ * read() from the device, but it seems like a too fragile
+ * solution as we have no clue about stuff in the buffer --
+ * maybe it was already modified. Let's re-read from the device
+ * to be sure. -- kzak 13-Apr-2015
+ */
+ DBG(CXT, ul_debugobj(cxt, "first sector protection enabled -- re-reading"));
+ read_from_device(cxt, cxt->firstsector, protect_off, protect_size);
+ }
return 0;
}
int fdisk_read_firstsector(struct fdisk_context *cxt)
{
- ssize_t r;
int rc;
assert(cxt);
assert(cxt->sector_size);
- rc = fdisk_init_firstsector_buffer(cxt);
+ rc = fdisk_init_firstsector_buffer(cxt, 0, 0);
if (rc)
return rc;
assert(cxt->sector_size == cxt->firstsector_bufsz);
- DBG(CXT, ul_debugobj(cxt, "reading first sector "
- "buffer [sector_size=%lu]", cxt->sector_size));
-
- r = lseek(cxt->dev_fd, 0, SEEK_SET);
- if (r == -1)
- {
- DBG(CXT, ul_debugobj(cxt, "failed to seek to first sector %m"));
- return -errno;
- }
-
- r = read(cxt->dev_fd, cxt->firstsector, cxt->sector_size);
- if (r != cxt->sector_size) {
- if (!errno)
- errno = EINVAL; /* probably too small file/device */
- DBG(CXT, ul_debugobj(cxt, "failed to read first sector %m"));
- return -errno;
- }
-
- return 0;
+ return read_from_device(cxt, cxt->firstsector, 0, cxt->sector_size);
}
/**