Created
December 15, 2014 23:48
-
-
Save tuxillo/6c704b1fc8d55df3b2d8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/sbin/disklabel64/disklabel64.c b/sbin/disklabel64/disklabel64.c | |
index afd77ec..05d4747 100644 | |
--- a/sbin/disklabel64/disklabel64.c | |
+++ b/sbin/disklabel64/disklabel64.c | |
@@ -119,8 +119,11 @@ extern uint32_t crc32(const void *buf, size_t size); | |
#define BIG_NEWFS_FRAG 2048U | |
#define BIG_NEWFS_CPG 64U | |
+#define PARTOFF(p) (parts[p-1].dp_start * 512LU) | |
+ | |
void makelabel(const char *, const char *, struct disklabel64 *); | |
int writelabel(int, struct disklabel64 *); | |
+static void readpartdata(int); | |
void l_perror(const char *); | |
struct disklabel64 *readlabel(int); | |
struct disklabel64 *makebootarea(int); | |
@@ -140,6 +143,7 @@ struct disklabel64 *getvirginlabel(void); | |
#define DEFEDITOR _PATH_VI | |
#define streq(a,b) (strcmp(a,b) == 0) | |
+int is_file; | |
char *dkname; | |
char *specname; | |
char tmpfil[] = PATH_TMPFILE; | |
@@ -151,7 +155,9 @@ struct disklabel64 lab; | |
char part_size_type[MAX_NUM_PARTS]; | |
char part_offset_type[MAX_NUM_PARTS]; | |
int part_set[MAX_NUM_PARTS]; | |
+struct dos_partition parts[4]; | |
+int partition; | |
int installboot; /* non-zero if we should install a boot program */ | |
int boot1size; | |
int boot1lsize; | |
@@ -172,15 +178,16 @@ u_int32_t slice_start_lba; | |
#ifdef DEBUG | |
int debug; | |
-#define OPTIONS "BNRWb:denrs:Vw" | |
+#define OPTIONS "BNRWb:denrs:Vwp:" | |
#else | |
-#define OPTIONS "BNRWb:enrs:Vw" | |
+#define OPTIONS "BNRWb:enrs:Vwp:" | |
#endif | |
int | |
main(int argc, char *argv[]) | |
{ | |
struct disklabel64 *lp; | |
+ struct stat st; | |
FILE *t; | |
int ch, f = 0, flag, error = 0; | |
char *name = NULL; | |
@@ -231,6 +238,12 @@ main(int argc, char *argv[]) | |
usage(); | |
op = WRITE; | |
break; | |
+ case 'p': | |
+ partition = strtol(optarg, NULL, 10); | |
+ if (partition < 1 || partition > 4) | |
+ usage(); | |
+ break; | |
+ | |
#ifdef DEBUG | |
case 'd': | |
debug++; | |
@@ -255,12 +268,31 @@ main(int argc, char *argv[]) | |
if (argc < 1) | |
usage(); | |
- dkname = getdevpath(argv[0], 0); | |
- specname = dkname; | |
+ /* | |
+ * Check if we're passed a regular file. If so, set | |
+ * rflag as this is the only way to operate it, ioctl(2) | |
+ * won't work. | |
+ */ | |
+ if ((stat(argv[0], &st) != -1) | |
+ && (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode))) { | |
+ is_file = 1; | |
+ rflag++; | |
+ specname = argv[0]; | |
+ } else { | |
+ dkname = getdevpath(argv[0], 0); | |
+ specname = dkname; | |
+ } | |
f = open(specname, op == READ ? O_RDONLY : O_RDWR); | |
if (f < 0) | |
err(4, "%s", specname); | |
+ /* | |
+ * Read in all DOS partitions, starting sector | |
+ * offsets will be needed later on. | |
+ */ | |
+ if (is_file) | |
+ readpartdata(f); | |
+ | |
switch(op) { | |
case UNSPEC: | |
@@ -275,7 +307,9 @@ main(int argc, char *argv[]) | |
case NOWRITE: | |
flag = 0; | |
- if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) | |
+ if (is_file) | |
+ errx(4, "can't disable label writing for files"); | |
+ else if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) | |
err(4, "ioctl DIOCWLABEL"); | |
break; | |
@@ -329,7 +363,9 @@ main(int argc, char *argv[]) | |
case WRITEABLE: | |
flag = 1; | |
- if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) | |
+ if (is_file) | |
+ errx(4, "can't enable label writing for files"); | |
+ else if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) | |
err(4, "ioctl DIOCWLABEL"); | |
break; | |
@@ -353,6 +389,26 @@ main(int argc, char *argv[]) | |
} | |
/* | |
+ * Read dos partitions from file | |
+ */ | |
+static | |
+void | |
+readpartdata(int f) | |
+{ | |
+ char buf[512]; | |
+ ssize_t bytes; | |
+ | |
+ /* | |
+ * Read in DOS partitions to get the start offset | |
+ * for each one of them. | |
+ */ | |
+ if ((bytes = read(f, buf, 512)) < 512) | |
+ errx(1, "Unexpected error when reading from file %s\n", | |
+ specname); | |
+ memcpy(parts, &buf[DOSPARTOFF], sizeof(parts)); | |
+} | |
+ | |
+/* | |
* Construct a prototype disklabel from /etc/disktab. As a side | |
* effect, set the names of the primary and secondary boot files | |
* if specified. | |
@@ -422,12 +478,19 @@ writelabel(int f, struct disklabel64 *lp) | |
* consistency checks may prevent us from changing | |
* the current (in-core) label. | |
*/ | |
- if (ioctl(f, DIOCSDINFO64, lp) < 0 && | |
- errno != ENODEV && errno != ENOTTY) { | |
- l_perror("ioctl DIOCSDINFO"); | |
- return (1); | |
+ if (is_file) { | |
+ /* Seek file descriptor f to the desired offset */ | |
+ if (lseek(f, PARTOFF(partition), SEEK_SET) < 0) | |
+ err(1, "lseek"); | |
+ } else { | |
+ if (ioctl(f, DIOCSDINFO64, lp) < 0 && | |
+ errno != ENODEV && errno != ENOTTY) { | |
+ l_perror("ioctl DIOCSDINFO"); | |
+ return (1); | |
+ } | |
+ lseek(f, (off_t)0, SEEK_SET); | |
} | |
- lseek(f, (off_t)0, SEEK_SET); | |
+ | |
/* | |
* The disklabel embeds areas which we may not | |
@@ -440,13 +503,13 @@ writelabel(int f, struct disklabel64 *lp) | |
sizeof(*lp) - | |
offsetof(struct disklabel64, d_magic)); | |
} | |
- | |
+ | |
/* | |
* write enable label sector before write | |
* (if necessary), disable after writing. | |
*/ | |
flag = 1; | |
- if (ioctl(f, DIOCWLABEL, &flag) < 0) | |
+ if (!is_file && (ioctl(f, DIOCWLABEL, &flag) < 0)) | |
warn("ioctl DIOCWLABEL"); | |
r = write(f, boot1buf, boot1lsize); | |
@@ -465,8 +528,10 @@ writelabel(int f, struct disklabel64 *lp) | |
return(1); | |
} | |
} | |
- flag = 0; | |
- ioctl(f, DIOCWLABEL, &flag); | |
+ if (!is_file) { | |
+ flag = 0; | |
+ ioctl(f, DIOCWLABEL, &flag); | |
+ } | |
} else if (ioctl(f, DIOCWDINFO64, lp) < 0) { | |
l_perror("ioctl DIOCWDINFO64"); | |
return (1); | |
@@ -579,6 +644,12 @@ makebootarea(int f) | |
else | |
secsize = 512; | |
+ if (is_file) { | |
+ /* Seek file descriptor f to the desired offset */ | |
+ if (lseek(f, PARTOFF(partition), SEEK_SET) < 0) | |
+ err(1, "lseek"); | |
+ } | |
+ | |
if (boot1buf == NULL) { | |
size_t rsize; | |
@@ -1470,6 +1541,47 @@ checklabel(struct disklabel64 *lp) | |
} | |
/* | |
+ * Create a dummy disklabel for files | |
+ */ | |
+static | |
+void | |
+getvirginlabel_file(struct disklabel64 *lp) | |
+{ | |
+ struct stat st; | |
+ uint32_t blksize = 4096; /* XXX - hardcoding defaults uh? */ | |
+ uint32_t ressize; | |
+ uint64_t blkmask = blksize - 1; | |
+ size_t lpcrcsize; | |
+ | |
+ if (lp == NULL) | |
+ return; | |
+ | |
+ bzero(lp, sizeof(*lp)); | |
+ if (stat(specname, &st) < 0) | |
+ err(1, "Failed to stat file"); | |
+ lp->d_total_size = st.st_size; | |
+ lp->d_magic = DISKMAGIC64; | |
+ lp->d_align = blksize; | |
+ lp->d_npartitions = MAXPARTITIONS64; | |
+ uuidgen(&lp->d_stor_uuid, 1); | |
+ | |
+ ressize = offsetof(struct disklabel64, d_partitions[RESPARTITIONS64]); | |
+ ressize = (ressize + (uint32_t)blkmask) & ~blkmask; | |
+ | |
+ lp->d_bbase = ressize; | |
+// lp->d_pbase = lp->d_bbase + ((32768 + blkmask) & ~blkmask); | |
+// lp->d_pbase = (lp->d_pbase + PALIGN_MASK) & ~(uint64_t)PALIGN_MASK; | |
+ | |
+ lp->d_pbase += 32768 - (PARTOFF(partition)) % 32768; | |
+ lp->d_pstop = (lp->d_total_size - lp->d_bbase) & ~blkmask; | |
+ lp->d_abase = lp->d_pstop; | |
+ lpcrcsize = offsetof(struct disklabel64, | |
+ d_partitions[lp->d_npartitions]) - | |
+ offsetof(struct disklabel64, d_magic); | |
+ lp->d_crc = crc32(&lp->d_magic, lpcrcsize); | |
+} | |
+ | |
+/* | |
* When operating on a "virgin" disk, try getting an initial label | |
* from the associated device driver. This might work for all device | |
* drivers that are able to fetch some initial device parameters | |
@@ -1486,6 +1598,11 @@ getvirginlabel(void) | |
struct disklabel64 *dl = &dlab; | |
int f; | |
+ if (is_file) { | |
+ getvirginlabel_file(dl); | |
+ return (dl); | |
+ } | |
+ | |
if ((f = open(dkname, O_RDONLY)) == -1) { | |
warn("cannot open %s", dkname); | |
return (NULL); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment