tech-userlevel archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Making fdisk accept percentages (and modifiers on shell)



Hi,

it might be useful (and specially IS, for me ;) to have fdisk specify
percentages instead of absolute size values.
Thus, the attached patches do exactly that, and they also extend the current
modifiers (MB, GB, cyl) to batch-mode (-s). Then, TB was added (though
unnecessary, but you don't have to use four digit GB sizes).

Any comments about that?

Regards, Julian
--- sbin/fdisk/fdisk.8
+++ sbin/fdisk/fdisk.8
@@ -308,10 +308,11 @@
 .Ar size ,
 and optionally
 .Ar bootmenu .
 This flag requires the use of a partition selection flag
 .Pq Fl 0 , 1 , 2 , 3 , No or Fl E Ar number .
+.Pp
 .It Fl T Ar disktype
 Use the disklabel
 .Ar disktype
 instead of the disklabel on
 .Ar device .
@@ -339,11 +340,12 @@
 and
 .Em size
 can be specified in blocks (NN),
 cylinders (NNc or NNcyl),
 megabytes (NNm or NNMB),
-or gigabytes (NNg or NNGB), values in megabytes and gigabytes
+gigabytes (NNg or NNGB)
+or terabytes (NNt or NNTB) values in megabytes and gigabytes
 will be rounded to the nearest cylinder boundary.
 The
 .Em size
 may be specified as
 .Em $
@@ -553,10 +555,16 @@
 from the partition might fail.
 .Nx
 partitions may be made bootable using
 .Xr installboot 8 .
 .Sh NOTES
+You can modify the start and size values of partitions in interactive and
+in batch-mode by
+.Em tb , t , gb , g , mb , m , cyl , % ,
+specifying the number to be counted either in terabytes, gigabytes, 
+megabytes, cylinders or percentage of the whole disk size.
+.Pp
 This program is only available (and useful) on systems with PC-platform-style
 MBR partitioning.
 .Pp
 Traditionally the partition boundaries should be on cylinder boundaries
 using the BIOS geometry, with the exception of the first partition,

--- sbin/fdisk/fdisk.c
+++ sbin/fdisk/fdisk.c
@@ -271,10 +271,12 @@
 static void    get_ptn_alignmemt(void);
 #if defined(USE_DISKLIST)
 static void    get_diskname(const char *, char *, size_t);
 #endif
 static int     change_part(int, int, int, daddr_t, daddr_t, char *);
+static void    parse_partstr(char *, int *, daddr_t *, daddr_t *, char **);
+static int64_t parse_smodifier(const char *, int);
 static void    print_geometry(void);
 static int     first_active(void);
 static void    change_active(int);
 static void    change_bios_geometry(void);
 static void    dos(int, unsigned char *, unsigned char *, unsigned char *);
@@ -291,10 +293,11 @@
 #define DEC_SEC                1               /* asking for a sector number */
 #define        DEC_RND         2               /* round to end of first track 
*/
 #define        DEC_RND_0       4               /* convert 0 to size of a track 
*/
 #define DEC_RND_DOWN   8               /* subtract 1 track */
 #define DEC_RND_DOWN_2 16              /* subtract 2 tracks */
+#define DEC_RND_BNDY   32              /* round _down_ to boundary, instead of 
up. */
 static int     ptn_id(const char *, int *);
 static int     type_match(const void *, const void *);
 static const char *get_type(int);
 static int     get_mapping(int, unsigned int *, unsigned int *, unsigned int 
*, unsigned long *);
 #ifdef BOOTSEL
@@ -329,18 +332,19 @@
 {
        struct stat sb;
        int ch;
        size_t len;
        char *cp;
+       static char *partstr;
        int n;
 #ifdef BOOTSEL
        daddr_t default_ptn;            /* start sector of default ptn */
        char *cbootmenu = 0;
 #endif
 
        int csysid;     /* For the s_flag. */
-       unsigned int cstart, csize;
+       daddr_t cstart, csize;
        a_flag = u_flag = sh_flag = f_flag = s_flag = b_flag = 0;
        i_flag = B_flag = 0;
        v_flag = 0;
        E_flag = 0;
        csysid = cstart = csize = 0;
@@ -398,22 +402,13 @@
                case 'v':       /* Be verbose */
                        v_flag++;
                        break;
                case 's':       /* Partition details */
                        s_flag = 1;
-                       if (sscanf(optarg, "%d/%u/%u%n", &csysid, &cstart,
-                           &csize, &n) == 3) {
-                               if (optarg[n] == 0)
-                                       break;
-#ifdef BOOTSEL
-                               if (optarg[n] == '/') {
-                                       cbootmenu = optarg + n + 1;
-                                       break;
-                               }
-#endif
-                       }
-                       errx(1, "Bad argument to the -s flag.");
+                       partstr = strdup(optarg);
+                       if (!partstr)
+                               err(1, "Could not allocate string.");
                        break;
                case 'b':       /* BIOS geometry */
                        b_flag = 1;
                        if (sscanf(optarg, "%d/%d/%d%n", &b_cyl, &b_head,
                            &b_sec, &n) != 3 || optarg[n] != 0)
@@ -528,13 +523,21 @@
        /* Do the update stuff! */
        if (u_flag) {
                if (!f_flag && !b_flag)
                        change_bios_geometry();
 
-               if (s_flag)
+               if (s_flag) {
+                       parse_partstr(partstr, &csysid, &cstart, &csize, 
&cbootmenu);
+#ifndef BOOTSEL
+                       if (strlen(cbootmenu))
+                               errx(1, "Bad argument to the -s flag: Too many 
slashes.");
+#endif
+                       free(partstr);
+
                        change_part(E_flag, partition, csysid, cstart, csize,
                                cbootmenu);
+               }
                else {
                        int part = partition, chg_ext = E_flag, prompt = 1;
                        do {
                                if (prompt) {
                                        printf("\n");
@@ -1955,10 +1958,119 @@
                }
        }
        return 0;
 }
 
+/* This function has the same flags as the other round-determining stuff, but 
+ * one with a special meaning: DEC_RND_DOWN rounds also to the lower alignment
+ * boundary, instead of the upper one.
+ * We need this to have a total value of 100%. */
+static int64_t
+parse_smodifier(const char *sizestr, int flags)
+{
+       char *cp;
+       int64_t acc;
+       int valid;
+       int len;
+
+       if (!isdigit((unsigned char)*sizestr))
+               return -1;
+
+       acc = strtoll(sizestr, &cp, 10);
+       len = strcspn(cp, " \t\n");
+       valid = 0;
+       if (len != 0) {
+               if (!strncasecmp(cp, "tb", len)) {
+                       acc *= 1024;
+                       valid = 1;
+               }
+               if (valid || !strncasecmp(cp, "gb", len)) {
+                       acc *= 1024;
+                       valid = 1;
+               }
+               if (valid || !strncasecmp(cp, "mb", len)) {
+                       acc *= SEC_IN_1M;
+                       /* round to whole number of cylinders */
+                       acc += ptn_alignment / 2;
+                       acc /= ptn_alignment;
+                       valid = 1;
+               } else if (!strcmp(cp, "%")) {
+                       if (acc < 0 || acc > 100)
+                               return -1;
+                       acc = disksectors / 100 * acc;
+                       /* round to whole number of cylinders */
+                       if (acc <= ptn_alignment / 2)
+                               acc += ptn_alignment / 2;
+                       else if (flags & DEC_RND_DOWN)
+                               acc -= ptn_alignment / 2;
+                       else
+                               acc += ptn_alignment / 2;
+                       acc /= ptn_alignment;
+                       valid = 1;
+               }
+               if (valid || !strcasecmp(cp, "cyl")) {
+                       acc *= ptn_alignment;
+                       /* adjustments for cylinder boundary */
+                       if (acc == 0 && flags & DEC_RND_0)
+                               acc += ptn_0_offset;
+                       if (flags & DEC_RND)
+                               acc += ptn_0_offset;
+                       if (flags & DEC_RND_DOWN)
+                               acc -= ptn_0_offset;
+                       if (flags & DEC_RND_DOWN_2)
+                               acc -= ptn_0_offset;
+               }
+       }
+
+       return acc;
+}
+
+static void
+parse_partstr(char *partstr, int *csysid, daddr_t *cstart,
+       daddr_t *csize, char **cbootmenu)
+{
+       int64_t tval;
+       char *tmpstr;
+
+       /* Get sysid. */
+       tmpstr = strtok(partstr, "/");
+       if (tmpstr == NULL)
+               errx(1, "Bad argument to the -s flag.");
+       *csysid = strtoll(tmpstr, NULL, 10);
+       if (strspn(tmpstr, "1234567890") != strlen(tmpstr))
+               errx(1, "Bad id argument to the -s flag.");
+
+       /* Get start. */
+       tmpstr = strtok(NULL, "/");
+       if (tmpstr == NULL)
+               errx(1, "Bad argument to the -s flag.");
+       tval = parse_smodifier(tmpstr, DEC_RND);
+       if (tval < 0)
+               errx(1, "Bad start argument to the -s flag.");
+       *cstart = tval;
+
+       /* Get start. */
+       tmpstr = strtok(NULL, "/");
+       if (tmpstr == NULL)
+               errx(1, "Bad argument to the -s flag.");
+       tval = parse_smodifier(tmpstr, DEC_RND_DOWN);
+       if (tval < 0)
+               errx(1, "Bad size argument to the -s flag.");
+       *csize = tval;
+
+#ifdef BOOTSEL
+       /* Get bootmenu. */
+       tmpstr = strtok(NULL, "/");
+       if (tmpstr != NULL)
+               *cbootmenu = strdup(tmpstr);
+       else
+               *cbootmenu = NULL;
+#endif
+
+       return;
+}
+
 static int
 change_part(int extended, int part, int sysid, daddr_t start, daddr_t size,
        char *bootmenu)
 {
        struct mbr_partition *partp;
@@ -2766,18 +2878,36 @@
                if (isdigit((unsigned char)*cp) || *cp == '-') {
                        acc = strtoll(lbuf, &cp, 10);
                        len = strcspn(cp, " \t\n");
                        valid = 0;
                        if (len != 0 && (flags & DEC_SEC)) {
-                               if (!strncasecmp(cp, "gb", len)) {
+                               if (!strncasecmp(cp, "tb", len)) {
+                                       acc *= 1024;
+                                       valid = 1;
+                               }
+                               if (valid || !strncasecmp(cp, "gb", len)) {
                                        acc *= 1024;
                                        valid = 1;
                                }
                                if (valid || !strncasecmp(cp, "mb", len)) {
                                        acc *= SEC_IN_1M;
                                        /* round to whole number of cylinders */
                                        acc += ptn_alignment / 2;
+                                       acc /= ptn_alignment;
+                                       valid = 1;
+                               }
+                               if (!strncmp(cp, "%", len)) {
+                                       if (acc > 100)
+                                               return -1;
+                                       acc = disksectors / 100 * acc;
+                                       /* round to whole number of cylinders */
+                                       if (acc <= ptn_alignment / 2)
+                                               acc += ptn_alignment / 2;
+                                       else if (flags & DEC_RND_DOWN)
+                                               acc -= ptn_alignment / 2;
+                                       else
+                                               acc += ptn_alignment / 2;
                                        acc /= ptn_alignment;
                                        valid = 1;
                                }
                                if (valid || !strncasecmp(cp, "cyl", len)) {
                                        acc *= ptn_alignment;



Home | Main Index | Thread Index | Old Index