Enable operation of newfs on plain files, which is useful when you
want to prepare disk images for emulators (though 'makefs' in port can do something similar). This relies on: + minor changes to pass the consistency checks even when working on a file; + an additional option, '-p partition' , to specify the disk partition to initialize; + some changes on the I/O routines to deal with partition offsets. The latter was a bit tricky to implement, see the details in newfs.h: in newfs, I/O is done through libufs which assumes that the file descriptor refers to the whole partition. Introducing support for the offset in libufs would require a non-backward compatible change in the library, to be dealt with a version bump or with symbol versioning. I felt both approaches to be overkill for this specific application, especially because there might be other changes to libufs that might become necessary in the near future. So I used the following trick: - read access is always done by calling bread() directly, so we just add the offset in the (few) places that call bread(); - write access is done through bwrite() and sbwrite(), which in turn calls bwrite(). To avoid rewriting sbwrite(), we supply our own version of bwrite() here, which takes precedence over the version in libufs. MFC after: 4 weeks
This commit is contained in:
parent
b87d1601b6
commit
64c8fef580
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=185588
@ -1,10 +1,13 @@
|
|||||||
# @(#)Makefile 8.2 (Berkeley) 3/27/94
|
# @(#)Makefile 8.2 (Berkeley) 3/27/94
|
||||||
# $FreeBSD$
|
# $FreeBSD$
|
||||||
|
|
||||||
|
.PATH: ${.CURDIR}/../../sys/geom
|
||||||
|
|
||||||
PROG= newfs
|
PROG= newfs
|
||||||
DPADD= ${LIBUFS}
|
DPADD= ${LIBUFS}
|
||||||
LDADD= -lufs
|
LDADD= -lufs
|
||||||
SRCS= newfs.c mkfs.c
|
SRCS= newfs.c mkfs.c geom_bsd_enc.c
|
||||||
|
|
||||||
WARNS?= 2
|
WARNS?= 2
|
||||||
MAN= newfs.8
|
MAN= newfs.8
|
||||||
|
|
||||||
|
@ -459,7 +459,7 @@ mkfs(struct partition *pp, char *fsys)
|
|||||||
* Wipe out old UFS1 superblock(s) if necessary.
|
* Wipe out old UFS1 superblock(s) if necessary.
|
||||||
*/
|
*/
|
||||||
if (!Nflag && Oflag != 1) {
|
if (!Nflag && Oflag != 1) {
|
||||||
i = bread(&disk, SBLOCK_UFS1 / disk.d_bsize, chdummy, SBLOCKSIZE);
|
i = bread(&disk, part_ofs + SBLOCK_UFS1 / disk.d_bsize, chdummy, SBLOCKSIZE);
|
||||||
if (i == -1)
|
if (i == -1)
|
||||||
err(1, "can't read old UFS1 superblock: %s", disk.d_error);
|
err(1, "can't read old UFS1 superblock: %s", disk.d_error);
|
||||||
|
|
||||||
@ -872,7 +872,7 @@ alloc(int size, int mode)
|
|||||||
{
|
{
|
||||||
int i, d, blkno, frag;
|
int i, d, blkno, frag;
|
||||||
|
|
||||||
bread(&disk, fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg,
|
bread(&disk, part_ofs + fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg,
|
||||||
sblock.fs_cgsize);
|
sblock.fs_cgsize);
|
||||||
if (acg.cg_magic != CG_MAGIC) {
|
if (acg.cg_magic != CG_MAGIC) {
|
||||||
printf("cg 0: bad magic number\n");
|
printf("cg 0: bad magic number\n");
|
||||||
@ -925,7 +925,7 @@ iput(union dinode *ip, ino_t ino)
|
|||||||
int c;
|
int c;
|
||||||
|
|
||||||
c = ino_to_cg(&sblock, ino);
|
c = ino_to_cg(&sblock, ino);
|
||||||
bread(&disk, fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg,
|
bread(&disk, part_ofs + fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg,
|
||||||
sblock.fs_cgsize);
|
sblock.fs_cgsize);
|
||||||
if (acg.cg_magic != CG_MAGIC) {
|
if (acg.cg_magic != CG_MAGIC) {
|
||||||
printf("cg 0: bad magic number\n");
|
printf("cg 0: bad magic number\n");
|
||||||
@ -942,7 +942,7 @@ iput(union dinode *ip, ino_t ino)
|
|||||||
exit(32);
|
exit(32);
|
||||||
}
|
}
|
||||||
d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
|
d = fsbtodb(&sblock, ino_to_fsba(&sblock, ino));
|
||||||
bread(&disk, d, (char *)iobuf, sblock.fs_bsize);
|
bread(&disk, part_ofs + d, (char *)iobuf, sblock.fs_bsize);
|
||||||
if (sblock.fs_magic == FS_UFS1_MAGIC)
|
if (sblock.fs_magic == FS_UFS1_MAGIC)
|
||||||
((struct ufs1_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] =
|
((struct ufs1_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] =
|
||||||
ip->dp1;
|
ip->dp1;
|
||||||
|
@ -52,6 +52,7 @@
|
|||||||
.Op Fl i Ar bytes
|
.Op Fl i Ar bytes
|
||||||
.Op Fl m Ar free-space
|
.Op Fl m Ar free-space
|
||||||
.Op Fl o Ar optimization
|
.Op Fl o Ar optimization
|
||||||
|
.Op Fl p Ar partition
|
||||||
.Op Fl r Ar reserved
|
.Op Fl r Ar reserved
|
||||||
.Op Fl s Ar size
|
.Op Fl s Ar size
|
||||||
.Ar special
|
.Ar special
|
||||||
@ -201,6 +202,17 @@ the default is to optimize for
|
|||||||
See
|
See
|
||||||
.Xr tunefs 8
|
.Xr tunefs 8
|
||||||
for more details on how to set this option.
|
for more details on how to set this option.
|
||||||
|
.It Fl p Ar partition
|
||||||
|
The partition name (a..h) you want to use in case the underlying image
|
||||||
|
is a file, so you don't have access to individual partitions through the
|
||||||
|
filesystem.
|
||||||
|
Can also be used with a device, e.g.
|
||||||
|
.Nm
|
||||||
|
.Fl p Ar f
|
||||||
|
.Ar /dev/da1s3
|
||||||
|
is equivalent to
|
||||||
|
.Nm
|
||||||
|
.Ar /dev/da1s3f .
|
||||||
.It Fl r Ar reserved
|
.It Fl r Ar reserved
|
||||||
The size, in sectors, of reserved space
|
The size, in sectors, of reserved space
|
||||||
at the end of the partition specified in
|
at the end of the partition specified in
|
||||||
|
@ -139,6 +139,9 @@ u_char *volumelabel = NULL; /* volume label for filesystem */
|
|||||||
struct uufsd disk; /* libufs disk structure */
|
struct uufsd disk; /* libufs disk structure */
|
||||||
|
|
||||||
static char device[MAXPATHLEN];
|
static char device[MAXPATHLEN];
|
||||||
|
static u_char bootarea[BBSIZE];
|
||||||
|
static int is_file; /* work on a file, not a device */
|
||||||
|
static char *dkname;
|
||||||
static char *disktype;
|
static char *disktype;
|
||||||
static int unlabeled;
|
static int unlabeled;
|
||||||
|
|
||||||
@ -147,6 +150,18 @@ static struct disklabel *getdisklabel(char *s);
|
|||||||
static void rewritelabel(char *s, struct disklabel *lp);
|
static void rewritelabel(char *s, struct disklabel *lp);
|
||||||
static void usage(void);
|
static void usage(void);
|
||||||
|
|
||||||
|
ufs2_daddr_t part_ofs; /* partition offset in blocks, used with files */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* need to replace the library's bwrite so that sbwrite uses this one
|
||||||
|
*/
|
||||||
|
ssize_t
|
||||||
|
bwrite(struct uufsd *disk, ufs2_daddr_t blockno, const void *data, size_t size)
|
||||||
|
{
|
||||||
|
return pwrite(disk->d_fd, data, size,
|
||||||
|
(off_t)((part_ofs + blockno) * disk->d_bsize));
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *argv[])
|
main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
@ -158,7 +173,9 @@ main(int argc, char *argv[])
|
|||||||
intmax_t reserved;
|
intmax_t reserved;
|
||||||
int ch, i;
|
int ch, i;
|
||||||
off_t mediasize;
|
off_t mediasize;
|
||||||
|
char part_name; /* partition name, default to full disk */
|
||||||
|
|
||||||
|
part_name = 'c';
|
||||||
reserved = 0;
|
reserved = 0;
|
||||||
while ((ch = getopt(argc, argv,
|
while ((ch = getopt(argc, argv,
|
||||||
"EJL:NO:RS:T:UXa:b:c:d:e:f:g:h:i:lm:no:r:s:")) != -1)
|
"EJL:NO:RS:T:UXa:b:c:d:e:f:g:h:i:lm:no:r:s:")) != -1)
|
||||||
@ -276,6 +293,11 @@ main(int argc, char *argv[])
|
|||||||
*cp != '\0' || reserved < 0)
|
*cp != '\0' || reserved < 0)
|
||||||
errx(1, "%s: bad reserved size", optarg);
|
errx(1, "%s: bad reserved size", optarg);
|
||||||
break;
|
break;
|
||||||
|
case 'p':
|
||||||
|
is_file = 1;
|
||||||
|
part_name = optarg[0];
|
||||||
|
break;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
errno = 0;
|
errno = 0;
|
||||||
fssize = strtoimax(optarg, &cp, 0);
|
fssize = strtoimax(optarg, &cp, 0);
|
||||||
@ -294,6 +316,8 @@ main(int argc, char *argv[])
|
|||||||
usage();
|
usage();
|
||||||
|
|
||||||
special = argv[0];
|
special = argv[0];
|
||||||
|
if (!special[0])
|
||||||
|
err(1, "empty file/special name");
|
||||||
cp = strrchr(special, '/');
|
cp = strrchr(special, '/');
|
||||||
if (cp == 0) {
|
if (cp == 0) {
|
||||||
/*
|
/*
|
||||||
@ -303,7 +327,16 @@ main(int argc, char *argv[])
|
|||||||
special = device;
|
special = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ufs_disk_fillout_blank(&disk, special) == -1 ||
|
if (is_file) {
|
||||||
|
/* bypass ufs_disk_fillout_blank */
|
||||||
|
bzero( &disk, sizeof(disk));
|
||||||
|
disk.d_bsize = 1;
|
||||||
|
disk.d_name = special;
|
||||||
|
disk.d_fd = open(special, O_RDONLY);
|
||||||
|
if (disk.d_fd < 0 ||
|
||||||
|
(!Nflag && ufs_disk_write(&disk) == -1))
|
||||||
|
errx(1, "%s: ", special);
|
||||||
|
} else if (ufs_disk_fillout_blank(&disk, special) == -1 ||
|
||||||
(!Nflag && ufs_disk_write(&disk) == -1)) {
|
(!Nflag && ufs_disk_write(&disk) == -1)) {
|
||||||
if (disk.d_error != NULL)
|
if (disk.d_error != NULL)
|
||||||
errx(1, "%s: %s", special, disk.d_error);
|
errx(1, "%s: %s", special, disk.d_error);
|
||||||
@ -312,22 +345,30 @@ main(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
if (fstat(disk.d_fd, &st) < 0)
|
if (fstat(disk.d_fd, &st) < 0)
|
||||||
err(1, "%s", special);
|
err(1, "%s", special);
|
||||||
if ((st.st_mode & S_IFMT) != S_IFCHR)
|
if ((st.st_mode & S_IFMT) != S_IFCHR) {
|
||||||
errx(1, "%s: not a character-special device", special);
|
warn("%s: not a character-special device", special);
|
||||||
|
is_file = 1; /* assume it is a file */
|
||||||
|
dkname = special;
|
||||||
|
if (sectorsize == 0)
|
||||||
|
sectorsize = 512;
|
||||||
|
mediasize = st.st_size;
|
||||||
|
/* set fssize from the partition */
|
||||||
|
} else {
|
||||||
|
part_name = special[strlen(special) - 1];
|
||||||
|
if ((part_name < 'a' || part_name > 'h') && !isdigit(part_name))
|
||||||
|
errx(1, "%s: can't figure out file system partition",
|
||||||
|
special);
|
||||||
|
|
||||||
if (sectorsize == 0)
|
if (sectorsize == 0)
|
||||||
if (ioctl(disk.d_fd, DIOCGSECTORSIZE, §orsize) == -1)
|
if (ioctl(disk.d_fd, DIOCGSECTORSIZE, §orsize) == -1)
|
||||||
sectorsize = 0; /* back out on error for safety */
|
sectorsize = 0; /* back out on error for safety */
|
||||||
if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize) != -1)
|
if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize) != -1)
|
||||||
getfssize(&fssize, special, mediasize / sectorsize, reserved);
|
getfssize(&fssize, special, mediasize / sectorsize, reserved);
|
||||||
|
}
|
||||||
pp = NULL;
|
pp = NULL;
|
||||||
lp = getdisklabel(special);
|
lp = getdisklabel(special);
|
||||||
if (lp != NULL) {
|
if (lp != NULL) {
|
||||||
cp = strchr(special, '\0');
|
cp = &part_name;
|
||||||
cp--;
|
|
||||||
if ((*cp < 'a' || *cp > 'h') && !isdigit(*cp))
|
|
||||||
errx(1, "%s: can't figure out file system partition",
|
|
||||||
special);
|
|
||||||
if (isdigit(*cp))
|
if (isdigit(*cp))
|
||||||
pp = &lp->d_partitions[RAW_PART];
|
pp = &lp->d_partitions[RAW_PART];
|
||||||
else
|
else
|
||||||
@ -346,6 +387,8 @@ main(int argc, char *argv[])
|
|||||||
fsize = pp->p_fsize;
|
fsize = pp->p_fsize;
|
||||||
if (bsize == 0)
|
if (bsize == 0)
|
||||||
bsize = pp->p_frag * pp->p_fsize;
|
bsize = pp->p_frag * pp->p_fsize;
|
||||||
|
if (is_file)
|
||||||
|
part_ofs = pp->p_offset;
|
||||||
}
|
}
|
||||||
if (sectorsize <= 0)
|
if (sectorsize <= 0)
|
||||||
errx(1, "%s: no default sector size", special);
|
errx(1, "%s: no default sector size", special);
|
||||||
@ -414,6 +457,19 @@ getdisklabel(char *s)
|
|||||||
static struct disklabel lab;
|
static struct disklabel lab;
|
||||||
struct disklabel *lp;
|
struct disklabel *lp;
|
||||||
|
|
||||||
|
if (is_file) {
|
||||||
|
if (read(disk.d_fd, bootarea, BBSIZE) != BBSIZE)
|
||||||
|
err(4, "cannot read bootarea");
|
||||||
|
if (bsd_disklabel_le_dec(
|
||||||
|
bootarea + (0 /* labeloffset */ +
|
||||||
|
1 /* labelsoffset */ * sectorsize),
|
||||||
|
&lab, MAXPARTITIONS))
|
||||||
|
errx(1, "no valid label found");
|
||||||
|
|
||||||
|
lp = &lab;
|
||||||
|
return &lab;
|
||||||
|
}
|
||||||
|
|
||||||
if (ioctl(disk.d_fd, DIOCGDINFO, (char *)&lab) != -1)
|
if (ioctl(disk.d_fd, DIOCGDINFO, (char *)&lab) != -1)
|
||||||
return (&lab);
|
return (&lab);
|
||||||
unlabeled++;
|
unlabeled++;
|
||||||
@ -432,6 +488,14 @@ rewritelabel(char *s, struct disklabel *lp)
|
|||||||
return;
|
return;
|
||||||
lp->d_checksum = 0;
|
lp->d_checksum = 0;
|
||||||
lp->d_checksum = dkcksum(lp);
|
lp->d_checksum = dkcksum(lp);
|
||||||
|
if (is_file) {
|
||||||
|
bsd_disklabel_le_enc(bootarea + 0 /* labeloffset */ +
|
||||||
|
1 /* labelsoffset */ * sectorsize, lp);
|
||||||
|
lseek(disk.d_fd, 0, SEEK_SET);
|
||||||
|
if (write(disk.d_fd, bootarea, BBSIZE) != BBSIZE)
|
||||||
|
errx(1, "cannot write label");
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (ioctl(disk.d_fd, DIOCWDINFO, (char *)lp) == -1)
|
if (ioctl(disk.d_fd, DIOCWDINFO, (char *)lp) == -1)
|
||||||
warn("ioctl (WDINFO): %s: can't rewrite disk label", s);
|
warn("ioctl (WDINFO): %s: can't rewrite disk label", s);
|
||||||
}
|
}
|
||||||
@ -467,6 +531,7 @@ usage()
|
|||||||
fprintf(stderr, "\t-n do not create .snap directory\n");
|
fprintf(stderr, "\t-n do not create .snap directory\n");
|
||||||
fprintf(stderr, "\t-m minimum free space %%\n");
|
fprintf(stderr, "\t-m minimum free space %%\n");
|
||||||
fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
|
fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
|
||||||
|
fprintf(stderr, "\t-p partition name (a..h)\n");
|
||||||
fprintf(stderr, "\t-r reserved sectors at the end of device\n");
|
fprintf(stderr, "\t-r reserved sectors at the end of device\n");
|
||||||
fprintf(stderr, "\t-s file system size (sectors)\n");
|
fprintf(stderr, "\t-s file system size (sectors)\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -70,4 +70,20 @@ extern int avgfilesperdir; /* expected number of files per directory */
|
|||||||
extern u_char *volumelabel; /* volume label for filesystem */
|
extern u_char *volumelabel; /* volume label for filesystem */
|
||||||
extern struct uufsd disk; /* libufs disk structure */
|
extern struct uufsd disk; /* libufs disk structure */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* To override a limitation in libufs, export the offset (in sectors) of the
|
||||||
|
* partition on the underlying media (file or disk). The value is used as
|
||||||
|
* an offset for all accesses to the media through bread(), which is only
|
||||||
|
* invoked directly in this program.
|
||||||
|
* For bwrite() we need a different approach, namely override the library
|
||||||
|
* version with one defined here. This is because bwrite() is called also
|
||||||
|
* by the library function sbwrite() which we cannot intercept nor want to
|
||||||
|
* rewrite. As a consequence, the internal version of bwrite() adds the
|
||||||
|
* partition offset itself when calling the underlying function, pwrite().
|
||||||
|
*
|
||||||
|
* XXX This info really ought to go into the struct uufsd, at which point
|
||||||
|
* we can remove the above hack.
|
||||||
|
*/
|
||||||
|
extern ufs2_daddr_t part_ofs; /* partition offset in blocks */
|
||||||
|
|
||||||
void mkfs (struct partition *, char *);
|
void mkfs (struct partition *, char *);
|
||||||
|
Loading…
Reference in New Issue
Block a user