Hi, There was an error in the rounding, please use the attached patch for main.c instead of the original one. > > the following patches are my supposal for: > > > * Adding a batch mode (option -s) > > I don't necessarily object, but does the -i interactive mode require a > tty? Otherwise isn't it similar in functionality to -s ? We also have > the -R option to apply a label from a file (I personally used the > latter often). Handling -i from shell is just difficult to handle (input redirection from file, error handling, etc.). The option -s is mostly consistent with fdisk one's. Reading the label from a file is also difficult to handle (print disklabel to file, *sed magic*, reading disklabel). There was afaik as well no support for size modifiers as in interactive mode (though that could be added, of course). > Just as a note, since this domain interests you, disklabel can only > handle partition sizes restricted by 32-bit, while gpt(8) can handle > larger sizes and is likely to become more widely used in the future. I > personally never used it, but it's also possible that you'd find that > gpt(8) also requires user-friendliness improvements... For gpt(8), I'm still not really sure about the state (see http://mail-index.netbsd.org/tech-userlevel/2011/10/16/msg005573.html). Regards, Julian
--- sbin/disklabel/main.c +++ sbin/disklabel/main.c @@ -108,10 +108,12 @@ #else #include <sys/ioctl.h> #include <sys/disklabel.h> #include <sys/disklabel_acorn.h> #include <sys/bootblock.h> +#include <sys/sysctl.h> +#include <sys/param.h> #include <util.h> #include <disktab.h> #endif /* HAVE_NBTOOL_CONFIG_H */ #include "pathnames.h" @@ -155,10 +157,11 @@ static int Iflag; /* Read/write direct, but default if absent */ static int lflag; /* List all known file system types and exit */ static int mflag; /* Expect disk to contain an MBR */ static int verbose; static int read_all; /* set if op = READ && Aflag */ +int ptn_alignment = 1; /* Partition alignment. extern in extern.h */ static int write_label(int); static int readlabel_direct(int); static void writelabel_direct(int); static int update_label(int, u_int, u_int); @@ -265,15 +268,18 @@ main(int argc, char *argv[]) { FILE *t; int ch, f, error; char *dkname; + char *partstr = NULL; + char *labelstr = NULL; + char *alignstr = NULL; struct stat sb; int writable; enum { UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, SETREADONLY, - WRITE, INTERACT, DELETE + WRITE, INTERACT, DELETE, BATCH } op = UNSPEC, old_op; mflag = GETLABELUSESMBR(); if (mflag < 0) { warn("getlabelusesmbr() failed"); @@ -283,11 +289,11 @@ /* We must avoid doing any ioctl requests */ Fflag = rflag = 1; #endif error = 0; - while ((ch = getopt(argc, argv, "ACDFINRWb:ef:ilmrs:tvw")) != -1) { + while ((ch = getopt(argc, argv, "ACDFINRWa:ef:s:p:uilmrtvw")) != -1) { old_op = op; switch (ch) { case 'A': /* Action all labels */ Aflag = 1; rflag = 1; @@ -314,10 +320,15 @@ op = SETREADONLY; break; case 'W': /* Allow writes to label sector */ op = SETWRITABLE; break; + case 'a': /* Set partition alignment */ + alignstr = strdup(optarg); + if (!alignstr) + err(1, "Could not allocate string."); + break; case 'e': /* Edit label with $EDITOR */ op = EDIT; break; case 'f': /* Name of disktab file */ if (setdisktab(optarg) == -1) @@ -330,10 +341,15 @@ lflag = 1; break; case 'm': /* Expect disk to have an MBR */ mflag ^= 1; break; + case 'p': /* Change disklabel values */ + labelstr = strdup(optarg); + if (!labelstr) + err(1, "Could not allocate string."); + break; case 'r': /* Read/write label directly from disk */ rflag = 1; break; case 't': /* Format output as a disktab entry */ tflag = 1; @@ -341,10 +357,18 @@ case 'v': /* verbose/diag output */ verbose++; break; case 'w': /* Write label based on disktab entry */ op = WRITE; + break; + case 's': /* Preset partition values. */ + partstr = strdup(optarg); + if (!partstr) + err(1, "Could not allocate string."); + break; + case 'u': /* Update label without further interaction. */ + op = BATCH; break; case '?': default: usage(); } @@ -381,22 +405,41 @@ if (argc != 1) usage(); Dflag = 2; writelabel_direct(f); break; + + case BATCH: + if (argc != 1) + usage(); + readlabel(f); + set_ptn_alignment(&lab, alignstr); + free(alignstr); + parse_partstr(&lab, &partstr); + parse_labelstr(&lab, &labelstr); + batchedit(&lab, f); + break; case EDIT: if (argc != 1) usage(); readlabel(f); + set_ptn_alignment(&lab, alignstr); + free(alignstr); + parse_partstr(&lab, &partstr); + parse_labelstr(&lab, &labelstr); error = edit(f); break; case INTERACT: if (argc != 1) usage(); readlabel(f); + set_ptn_alignment(&lab, alignstr); + free(alignstr); + parse_partstr(&lab, &partstr); + parse_labelstr(&lab, &labelstr); /* * XXX: Fill some default values so checklabel does not fail */ if (lab.d_bbsize == 0) lab.d_bbsize = BBSIZE; @@ -414,10 +457,14 @@ /* Label got printed in the bowels of readlabel */ break; if (tflag) makedisktab(stdout, &lab); else { + set_ptn_alignment(&lab, alignstr); + free(alignstr); + parse_partstr(&lab, &partstr); + parse_labelstr(&lab, &labelstr); showinfo(stdout, &lab, specname); showpartitions(stdout, &lab, Cflag); } error = checklabel(&lab); if (error) @@ -1906,6 +1953,128 @@ free(list); } } return ret; +} + +/* Convert a string to a uint16_t. Returns -1 on error, 0 on success. */ +int +strtouint16(char *intstr, uint16_t *val16) +{ + long int lval; + char *endstr; + + lval = strtoll(intstr, &endstr, 10); + if (*endstr != '\0') + return -1; + if (lval > UINT16_MAX) + return -1; + + *val16 = (uint16_t) lval; + + return 0; +} + +/* Convert a string to a uint32_t. Returns -1 on error, 0 on success. */ +int +strtouint32(char *intstr, uint32_t *val32) +{ + long int lval; + char *endstr; + + lval = strtoll(intstr, &endstr, 10); + if (*endstr != '\0') + return -1; + if (lval > UINT32_MAX) + return -1; + + *val32 = (uint32_t) lval; + + return 0; +} + +/* Convert a string with modifier to int, return negative value on error. + * If rounding is 0, do not round. If rounding is 1, round. If rounding is 2, + * round down, if rounding is 3, round up. */ +intmax_t +modstrtoint(struct disklabel *lp, char *modstr, int rounding) +{ + char *cp; + intmax_t ret; + int len, part; + size_t partlen; + + ret = strtoll(modstr, &cp, 10); + len = strcspn(cp, " \t\n"); + if (modstr == cp) + return -1; + if (!strncasecmp(cp, "sector", len)) + {} + else if (!strncasecmp(cp, "tb", len)) /* Might be too long for int. */ + ret *= (intmax_t)(1024 * 1024 * 1024 / lp->d_secsize * 1024); + else if (!strncasecmp(cp, "gb", len)) + ret *= 1024 * 1024 * 1024 / lp->d_secsize; + else if (!strncasecmp(cp, "mb", len)) + ret *= 1024 * 1024 / lp->d_secsize; + else if (!strncasecmp(cp, "kb", len)) + ret *= 1024 / lp->d_secsize; + else if (!strncasecmp(cp, "cylinder", len)) + ret *= lp->d_secpercyl; + else if (!strncasecmp(cp, "%", len)) { + if (ret < 0 || ret > 100) + err(1, "Percentage must be in [0, 100], is %d.", ret); + /* lp->d_secperunit is the best approximation for the right value we can + * get. We cannot determine the mbr partition size for sure if there is + * one, so simply compute percentages of the whole disk. */ + // XXX: We could also use some magic involving checks of partition c, + // etc., to be sure to take percentages of the mbr. + ret *= lp->d_secperunit / lp->d_secsize / 100; + ret *= lp->d_secsize; + ret += ptn_alignment; + } else + return -1; + + switch (rounding) { + case 0: /* Nothing at all. */ + break; + case 1: /* Round. */ + ret = ((ret / ptn_alignment) + (ret % ptn_alignment ? 1 : 0)) * ptn_alignment; + break; + case 2: /* Round down. */ + ret = (ret / ptn_alignment) * ptn_alignment; + break; + } + + return ret; +} + +/* The alignment stuff is mostly copied from fdisk(8). */ +void +set_ptn_alignment(struct disklabel *lp, char *alignstr) +{ + intmax_t i; + + /* Default to using 'traditional' cylinder alignment */ + ptn_alignment = lp->d_secpercyl; + + if (alignstr != NULL) { + i = modstrtoint(lp, alignstr, 0); + if (i != -1) + ptn_alignment = (unsigned int)i; + else + errx(1, "Invalid alignment specifier."); + } else { + i = lp->d_partitions[0].p_offset + lp->d_partitions[0].p_size; + if (i != 0) { + if (!(i & 2047)) { + /* Should nearly always extend to 1MB */ + ptn_alignment = 2048; + } + } else { + /* Use 1MB alignment for large disks */ + if (lp->d_secperunit > 2048 * 1024 * 128) + ptn_alignment = 2048; + } + } + + return; }
Attachment:
signature.asc
Description: PGP signature