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