]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
libfdisk: make it possible to reset device properties
authorKarel Zak <kzak@redhat.com>
Fri, 24 May 2013 09:48:58 +0000 (11:48 +0200)
committerKarel Zak <kzak@redhat.com>
Mon, 16 Sep 2013 14:46:57 +0000 (16:46 +0200)
 - remember user C/H/S and sector size
 - reset all device properties before create a new label (maybe the
   old setting has been affected by previous on-disk label)
 - always apply user setting after the reset
 - improve topology/geometry debug messages

Note that for fdisk "user C/H/S and sector size" means on command line
specified values. If you override the setting by c/h/s commands in
expert menu then the setting is applied to the current disk label
only. If you create a new disk label (e.g change MBR to GPT) then
fdisk will use the original setting.

Signed-off-by: Karel Zak <kzak@redhat.com>
fdisks/fdisk.c
libfdisk/src/alignment.c
libfdisk/src/context.c
libfdisk/src/fdiskP.h
libfdisk/src/label.c
libfdisk/src/libfdisk.h

index 96cd71958d28edc152e55db6530b508227485237..12700ee6e3c42a14ceb00ae5102168b2d4c5d1b8 100644 (file)
@@ -58,9 +58,6 @@ char  *line_ptr,                      /* interactive input */
 
 int    nowarn = 0;                     /* no warnings for fdisk -l/-s */
 
-/* when C/H/S specified on command line */
-static unsigned int user_cylinders, user_heads, user_sectors;
-
 void toggle_units(struct fdisk_context *cxt)
 {
        fdisk_context_set_unit(cxt,
@@ -796,19 +793,13 @@ static int is_ide_cdrom_or_tape(char *device)
 }
 
 /* Print disk geometry and partition table of a specified device (-l option) */
-static void print_partition_table_from_option(struct fdisk_context *cxt,
-                               char *device, unsigned long sector_size)
+static void print_partition_table_from_option(
+                       struct fdisk_context *cxt,
+                       char *device)
 {
        if (fdisk_context_assign_device(cxt, device, 1) != 0)   /* read-only */
                err(EXIT_FAILURE, _("cannot open %s"), device);
 
-       if (sector_size) /* passed -b option, override autodiscovery */
-               fdisk_override_sector_size(cxt, sector_size);
-
-       if (user_cylinders || user_heads || user_sectors)
-               fdisk_override_geometry(cxt, user_cylinders,
-                                       user_heads, user_sectors);
-
        if (fdisk_dev_has_disklabel(cxt))
                list_table(cxt, 0);
        else
@@ -820,8 +811,7 @@ static void print_partition_table_from_option(struct fdisk_context *cxt,
  * try all things in /proc/partitions that look like a full disk
  */
 static void
-print_all_partition_table_from_option(struct fdisk_context *cxt,
-                                     unsigned long sector_size)
+print_all_partition_table_from_option(struct fdisk_context *cxt)
 {
        FILE *procpt;
        char line[128 + 1], ptname[128 + 1], devname[256];
@@ -843,7 +833,7 @@ print_all_partition_table_from_option(struct fdisk_context *cxt,
                        char *cn = canonicalize_path(devname);
                        if (cn) {
                                if (!is_ide_cdrom_or_tape(cn))
-                                       print_partition_table_from_option(cxt, cn, sector_size);
+                                       print_partition_table_from_option(cxt, cn);
                                free(cn);
                        }
                }
@@ -1029,9 +1019,13 @@ int main(int argc, char **argv)
                        if (sector_size != 512 && sector_size != 1024 &&
                            sector_size != 2048 && sector_size != 4096)
                                usage(stderr);
+                       fdisk_save_user_sector_size(cxt, sector_size, sector_size);
                        break;
                case 'C':
-                       user_cylinders =  strtou32_or_err(optarg, _("invalid cylinders argument"));
+                       fdisk_save_user_geometry(cxt,
+                               strtou32_or_err(optarg,
+                                               _("invalid cylinders argument")),
+                               0, 0);
                        break;
                case 'c':
                        if (optarg) {
@@ -1050,14 +1044,15 @@ int main(int argc, char **argv)
                        /* use default if no optarg specified */
                        break;
                case 'H':
-                       user_heads = strtou32_or_err(optarg, _("invalid heads argument"));
-                       if (user_heads > 256)
-                               user_heads = 0;
+                       fdisk_save_user_geometry(cxt, 0,
+                               strtou32_or_err(optarg,
+                                               _("invalid heads argument")),
+                               0);
                        break;
                case 'S':
-                       user_sectors =  strtou32_or_err(optarg, _("invalid sectors argument"));
-                       if (user_sectors >= 64)
-                               user_sectors = 0;
+                       fdisk_save_user_geometry(cxt, 0, 0,
+                               strtou32_or_err(optarg,
+                                       _("invalid sectors argument")));
                        break;
                case 'l':
                        optl = 1;
@@ -1092,9 +1087,9 @@ int main(int argc, char **argv)
                if (argc > optind) {
                        int k;
                        for (k = optind; k < argc; k++)
-                               print_partition_table_from_option(cxt, argv[k], sector_size);
+                               print_partition_table_from_option(cxt, argv[k]);
                } else
-                       print_all_partition_table_from_option(cxt, sector_size);
+                       print_all_partition_table_from_option(cxt);
                exit(EXIT_SUCCESS);
        }
 
@@ -1119,13 +1114,6 @@ int main(int argc, char **argv)
        if (fdisk_context_assign_device(cxt, argv[optind], 0) != 0)
                err(EXIT_FAILURE, _("cannot open %s"), argv[optind]);
 
-       if (sector_size)        /* passed -b option, override autodiscovery */
-               fdisk_override_sector_size(cxt, sector_size);
-
-       if (user_cylinders || user_heads || user_sectors)
-               fdisk_override_geometry(cxt, user_cylinders,
-                                               user_heads, user_sectors);
-
        print_welcome();
 
        if (!fdisk_dev_has_disklabel(cxt)) {
index b4d3ee01d955cebb5033075d98408225e41ebb62..9e7d33b67b29061d9c4acbce7bfc032a694fbafe 100644 (file)
@@ -74,6 +74,10 @@ sector_t fdisk_align_lba(struct fdisk_context *cxt, sector_t lba, int direction)
                }
        }
 
+       if (lba != res)
+               DBG(TOPOLOGY, dbgprint("LBA %ju -aligned-to-> %ju",
+                               (uintmax_t) lba,
+                               (uintmax_t) res));
        return res;
 }
 
@@ -114,30 +118,6 @@ static unsigned long get_sector_size(int fd)
        return DEFAULT_SECTOR_SIZE;
 }
 
-/**
- * fdisk_override_sector_size:
- * @cxt: fdisk context
- * @s: required sector size
- *
- * Overwrites logical and physical sector size. Note that the default sector
- * size is discovered by fdisk_new_context_from_device() from device topology.
- *
- * Don't use this function, rely on the default behavioer is more safe.
- *
- * Returns: 0 on success, < 0 on error.
- */
-int fdisk_override_sector_size(struct fdisk_context *cxt, sector_t s)
-{
-       if (!cxt)
-               return -EINVAL;
-
-       cxt->phy_sector_size = cxt->sector_size = s;
-       cxt->min_io_size = cxt->io_size = s;
-
-       fdisk_reset_alignment(cxt);
-       return 0;
-}
-
 static void recount_geometry(struct fdisk_context *cxt)
 {
        cxt->geom.cylinders = cxt->total_sectors /
@@ -151,7 +131,8 @@ static void recount_geometry(struct fdisk_context *cxt)
  * @heads: user specified heads
  * @sectors: user specified sectors
  *
- * Overrides autodiscovery and apply user specified geometry.
+ * Overrides autodiscovery and apply user specified geometry. The function
+ * fdisk_reset_device_properties() restores the original setting.
  *
  * Returns: 0 on success, < 0 on error.
  */
@@ -173,6 +154,118 @@ int fdisk_override_geometry(struct fdisk_context *cxt,
                recount_geometry(cxt);
 
        fdisk_reset_alignment(cxt);
+
+       DBG(GEOMETRY, dbgprint("override C/H/S: %u/%u/%u",
+               (unsigned) cxt->geom.cylinders,
+               (unsigned) cxt->geom.heads,
+               (unsigned) cxt->geom.sectors));
+
+       return 0;
+}
+
+int fdisk_save_user_geometry(struct fdisk_context *cxt,
+                           unsigned int cylinders,
+                           unsigned int heads,
+                           unsigned int sectors)
+{
+       if (!cxt)
+               return -EINVAL;
+
+       cxt->user_geom.heads = heads > 256 ? 0 : heads;
+       cxt->user_geom.sectors = sectors >= 64 ? 0 : sectors;
+       cxt->user_geom.cylinders = cylinders;
+
+       DBG(GEOMETRY, dbgprint("user C/H/S: %u/%u/%u",
+                               cylinders, heads, sectors));
+
+       return 0;
+}
+
+int fdisk_save_user_sector_size(struct fdisk_context *cxt,
+                               unsigned int phy,
+                               unsigned int log)
+{
+       if (!cxt)
+               return -EINVAL;
+
+       DBG(TOPOLOGY, dbgprint("user phy/log sector size: %u/%u", phy, log));
+
+       cxt->user_pyh_sector = phy;
+       cxt->user_log_sector = log;
+
+       return 0;
+}
+
+int fdisk_apply_user_device_properties(struct fdisk_context *cxt)
+{
+       if (!cxt)
+               return -EINVAL;
+
+       DBG(TOPOLOGY, dbgprint("appling user device properties"));
+
+       if (cxt->user_pyh_sector)
+               cxt->phy_sector_size = cxt->user_pyh_sector;
+       if (cxt->user_log_sector)
+               cxt->sector_size = cxt->min_io_size =
+                       cxt->io_size = cxt->user_log_sector;
+
+       if (cxt->user_geom.heads)
+               cxt->geom.heads = cxt->user_geom.heads;
+       if (cxt->user_geom.sectors)
+               cxt->geom.sectors = cxt->user_geom.sectors;
+       if (cxt->user_geom.cylinders)
+               cxt->geom.cylinders = cxt->user_geom.cylinders;
+       else if (cxt->user_geom.heads || cxt->user_geom.sectors)
+               recount_geometry(cxt);
+
+       fdisk_reset_alignment(cxt);
+
+       DBG(GEOMETRY, dbgprint("new C/H/S: %u/%u/%u",
+               (unsigned) cxt->geom.cylinders,
+               (unsigned) cxt->geom.heads,
+               (unsigned) cxt->geom.sectors));
+       DBG(TOPOLOGY, dbgprint("new log/phy sector size: %u/%u",
+               (unsigned) cxt->sector_size,
+               (unsigned) cxt->phy_sector_size));
+
+       return 0;
+}
+
+void fdisk_zeroize_device_properties(struct fdisk_context *cxt)
+{
+       assert(cxt);
+
+       cxt->io_size = 0;
+       cxt->optimal_io_size = 0;
+       cxt->min_io_size = 0;
+       cxt->phy_sector_size = 0;
+       cxt->sector_size = 0;
+       cxt->alignment_offset = 0;
+       cxt->grain = 0;
+       cxt->first_lba = 0;
+       cxt->total_sectors = 0;
+
+       memset(&cxt->geom, 0, sizeof(struct fdisk_geometry));
+}
+
+int fdisk_reset_device_properties(struct fdisk_context *cxt)
+{
+       int rc;
+
+       if (!cxt)
+               return -EINVAL;
+
+       DBG(TOPOLOGY, dbgprint("*** reseting device properties"));
+
+       fdisk_zeroize_device_properties(cxt);
+       fdisk_discover_topology(cxt);
+       fdisk_discover_geometry(cxt);
+
+       rc = fdisk_read_firstsector(cxt);
+       if (rc)
+               return rc;
+
+       fdisk_apply_user_device_properties(cxt);
        return 0;
 }
 
@@ -187,6 +280,8 @@ int fdisk_discover_geometry(struct fdisk_context *cxt)
        assert(cxt);
        assert(cxt->geom.heads == 0);
 
+       DBG(GEOMETRY, dbgprint("%s: discovering geometry...", cxt->dev_path));
+
        /* get number of 512-byte sectors, and convert it the real sectors */
        if (!blkdev_get_sectors(cxt->dev_fd, &nsects))
                cxt->total_sectors = (nsects / (cxt->sector_size >> 9));
@@ -204,9 +299,10 @@ int fdisk_discover_geometry(struct fdisk_context *cxt)
        cxt->geom.sectors = s;
        recount_geometry(cxt);
 
-       DBG(GEOMETRY, dbgprint("geometry discovered for %s: C/H/S: %lld/%d/%lld",
-                              cxt->dev_path, cxt->geom.cylinders,
-                              cxt->geom.heads, cxt->geom.sectors));
+       DBG(GEOMETRY, dbgprint("result: C/H/S: %u/%u/%u",
+                              (unsigned) cxt->geom.cylinders,
+                              (unsigned) cxt->geom.heads,
+                              (unsigned) cxt->geom.sectors));
        return 0;
 }
 
@@ -218,6 +314,7 @@ int fdisk_discover_topology(struct fdisk_context *cxt)
        assert(cxt);
        assert(cxt->sector_size == 0);
 
+       DBG(TOPOLOGY, dbgprint("%s: discovering topology...", cxt->dev_path));
 #ifdef HAVE_LIBBLKID
        DBG(TOPOLOGY, dbgprint("initialize libblkid prober"));
 
@@ -251,11 +348,10 @@ int fdisk_discover_topology(struct fdisk_context *cxt)
        if (!cxt->io_size)
                cxt->io_size = cxt->sector_size;
 
-       DBG(TOPOLOGY, dbgprint("topology discovered for %s:\n"
-                              "\tlogical/physical sector sizes: %ld/%ld\n"
-                              "\tfdisk/minimal/optimal io sizes: %ld/%ld/%ld\n",
-                              cxt->dev_path, cxt->sector_size, cxt->phy_sector_size,
-                              cxt->io_size, cxt->optimal_io_size, cxt->min_io_size));
+       DBG(TOPOLOGY, dbgprint("result: log/phy sector size: %ld/%ld",
+                       cxt->sector_size, cxt->phy_sector_size));
+        DBG(TOPOLOGY, dbgprint("result: fdisk/min/optimal io: %ld/%ld/%ld",
+                      cxt->io_size, cxt->optimal_io_size, cxt->min_io_size));
        return 0;
 }
 
@@ -364,6 +460,8 @@ int fdisk_reset_alignment(struct fdisk_context *cxt)
        if (!cxt)
                return -EINVAL;
 
+       DBG(TOPOLOGY, dbgprint("reseting alignment..."));
+
        /* default */
        cxt->grain = fdisk_topology_get_grain(cxt);
        cxt->first_lba = fdisk_topology_get_first_lba(cxt);
index 6ede3e4687f7ee9f4c0d5bd98c1ccb1c417ee802..f2b0f7871093a9473af3d3c491e2fa11749f0613 100644 (file)
@@ -106,7 +106,7 @@ static void reset_context(struct fdisk_context *cxt)
 {
        size_t i;
 
-       DBG(CONTEXT, dbgprint("\n-----\nresetting context %p", cxt));
+       DBG(CONTEXT, dbgprint("*** resetting context %p", cxt));
 
        /* reset drives' private data */
        for (i = 0; i < cxt->nlabels; i++)
@@ -123,17 +123,7 @@ static void reset_context(struct fdisk_context *cxt)
        cxt->dev_path = NULL;
        cxt->firstsector = NULL;
 
-       cxt->io_size = 0;
-       cxt->optimal_io_size = 0;
-       cxt->min_io_size = 0;
-       cxt->phy_sector_size = 0;
-       cxt->sector_size = 0;
-       cxt->alignment_offset = 0;
-       cxt->grain = 0;
-       cxt->first_lba = 0;
-       cxt->total_sectors = 0;
-
-       memset(&cxt->geom, 0, sizeof(struct fdisk_geometry));
+       fdisk_zeroize_device_properties(cxt);
 
        cxt->label = NULL;
 }
@@ -179,7 +169,10 @@ int fdisk_context_assign_device(struct fdisk_context *cxt,
        /* detect labels and apply labes specific stuff (e.g geomery)
         * to the context */
        fdisk_probe_labels(cxt);
-       fdisk_reset_alignment(cxt);
+
+       /* let's apply user geometry *after* label prober
+        * to make it possible to override in-label setting */
+       fdisk_apply_user_device_properties(cxt);
 
        DBG(CONTEXT, dbgprint("context %p initialized for %s [%s]",
                              cxt, fname,
index 167670fcbb30b064289c32589fea7c95ed5db91d..9434f3213e6ca5b44d8441a5e1e685d17022047b 100644 (file)
@@ -272,9 +272,14 @@ struct fdisk_context {
        sector_t first_lba;             /* recommended begin of the first partition */
 
        /* geometry */
-       sector_t total_sectors; /* in logical sectors */
+       sector_t total_sectors; /* in logical sectors */
        struct fdisk_geometry geom;
 
+       /* user setting to overwrite device default */
+       struct fdisk_geometry user_geom;
+       unsigned long user_pyh_sector;
+       unsigned long user_log_sector;
+
        struct fdisk_label *label;      /* current label, pointer to labels[] */
 
        size_t nlabels;                 /* number of initialized label drivers */
@@ -314,7 +319,6 @@ extern sector_t fdisk_align_lba_in_range(struct fdisk_context *cxt, sector_t lba
                                         sector_t start, sector_t stop);
 
 
-extern int fdisk_override_sector_size(struct fdisk_context *cxt, sector_t s);
 extern int fdisk_override_geometry(struct fdisk_context *cxt,
                            unsigned int cylinders, unsigned int heads,
                             unsigned int sectors);
@@ -322,6 +326,9 @@ extern int fdisk_override_geometry(struct fdisk_context *cxt,
 extern int fdisk_discover_geometry(struct fdisk_context *cxt);
 extern int fdisk_discover_topology(struct fdisk_context *cxt);
 
+extern int fdisk_apply_user_device_properties(struct fdisk_context *cxt);
+extern void fdisk_zeroize_device_properties(struct fdisk_context *cxt);
+
 /* utils.c */
 extern void fdisk_zeroize_firstsector(struct fdisk_context *cxt);
 extern int fdisk_read_firstsector(struct fdisk_context *cxt);
index d518d876decfe15fe5244bda34debf0bd8e7662d..cabf3d751af86b8c80dad15bc5b1488b0cf2dae6 100644 (file)
@@ -182,6 +182,8 @@ int fdisk_delete_partition(struct fdisk_context *cxt, size_t partnum)
  */
 int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name)
 {
+       int haslabel = 0;
+
        if (!cxt)
                return -EINVAL;
 
@@ -193,8 +195,10 @@ int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name)
 #endif
        }
 
-       if (cxt->label)
+       if (cxt->label) {
                fdisk_deinit_label(cxt->label);
+               haslabel = 1;
+       }
 
        cxt->label = fdisk_context_get_label(cxt, name);
        if (!cxt->label)
@@ -204,7 +208,8 @@ int fdisk_create_disklabel(struct fdisk_context *cxt, const char *name)
        if (!cxt->label->op->create)
                return -ENOSYS;
 
-       fdisk_reset_alignment(cxt);
+       if (haslabel)
+               fdisk_reset_device_properties(cxt);
        return cxt->label->op->create(cxt);
 }
 
index fc38ef77054be10c26c96bf3c2f7947fc499cebb..3832af0703ae0da211a7520b9a5cb75b343ca0bc 100644 (file)
@@ -136,6 +136,16 @@ extern int fdisk_partition_toggle_flag(struct fdisk_context *cxt, size_t partnum
 
 /* alignment.c */
 extern int fdisk_reset_alignment(struct fdisk_context *cxt);
+extern int fdisk_reset_device_properties(struct fdisk_context *cxt);
+
+extern int fdisk_save_user_geometry(struct fdisk_context *cxt,
+                           unsigned int cylinders,
+                           unsigned int heads,
+                           unsigned int sectors);
+
+extern int fdisk_save_user_sector_size(struct fdisk_context *cxt,
+                               unsigned int phy,
+                               unsigned int log);
 
 
 /* dos.c */