tech-userlevel archive

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

Re: Making fdisk accept percentages (and modifiers on shell)



Hi,

> > Minor knits I just noticed ((more for the sake of being clean):
> > 
> > - meaningful errors when missing an argument in -s
> > - check for 'id' validity before converting via strtoll(3)
> Ok, thank you!
the attached patch includes your proposed fixes.

Regards, Julian
--- sbin/fdisk/fdisk.8
+++ sbin/fdisk/fdisk.8
@@ -308,10 +308,19 @@
 .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
+You can modify the values of
+.Ar start
+and
+.Ar size
+by
+.Em mb , gb , cyl , % ,
+then specifying the number being counted either in megabytes, gigabytes, 
+cylinders or percentage of the whole disk size.
 .It Fl T Ar disktype
 Use the disklabel
 .Ar disktype
 instead of the disklabel on
 .Ar device .

--- 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 *);
@@ -329,18 +331,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 +401,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 +522,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");
@@ -1953,10 +1955,99 @@
                                        ext.ptn[p].mbr_parts[0].mbrp_type = 0;
                        }
                }
        }
        return 0;
+}
+
+static int64_t
+parse_smodifier(const char *sizestr, int flags)
+{
+       char *cp;
+       int64_t acc;
+       int valid;
+
+       if (!isdigit((unsigned char)*sizestr))
+               return -1;
+
+       acc = strtoll(sizestr, &cp, 10);
+       valid = 0;
+       if (!strcasecmp(cp, "gb")) {
+               acc *= 1024;
+               valid = 1;
+       }
+       if (valid || !strcmp(cp, "%")) {
+               if (acc < 0 || acc > 100)
+                       return -1;
+               acc = disksectors / 100 * acc;
+       }
+       if (valid || !strcasecmp(cp, "mb")) {
+               acc *= SEC_IN_1M;
+               /* round to whole number of cylinders */
+               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)

Attachment: signature.asc
Description: PGP signature



Home | Main Index | Thread Index | Old Index