diff --git a/sbin/newfs/Makefile b/sbin/newfs/Makefile index efbe7abfe492..9454e5301444 100644 --- a/sbin/newfs/Makefile +++ b/sbin/newfs/Makefile @@ -1,10 +1,13 @@ # @(#)Makefile 8.2 (Berkeley) 3/27/94 # $FreeBSD$ +.PATH: ${.CURDIR}/../../sys/geom + PROG= newfs DPADD= ${LIBUFS} LDADD= -lufs -SRCS= newfs.c mkfs.c +SRCS= newfs.c mkfs.c geom_bsd_enc.c + WARNS?= 2 MAN= newfs.8 diff --git a/sbin/newfs/mkfs.c b/sbin/newfs/mkfs.c index b3bbcbf3b351..072e528113f9 100644 --- a/sbin/newfs/mkfs.c +++ b/sbin/newfs/mkfs.c @@ -459,7 +459,7 @@ mkfs(struct partition *pp, char *fsys) * Wipe out old UFS1 superblock(s) if necessary. */ 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) 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; - bread(&disk, fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg, + bread(&disk, part_ofs + fsbtodb(&sblock, cgtod(&sblock, 0)), (char *)&acg, sblock.fs_cgsize); if (acg.cg_magic != CG_MAGIC) { printf("cg 0: bad magic number\n"); @@ -925,7 +925,7 @@ iput(union dinode *ip, ino_t ino) int c; 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); if (acg.cg_magic != CG_MAGIC) { printf("cg 0: bad magic number\n"); @@ -942,7 +942,7 @@ iput(union dinode *ip, ino_t ino) exit(32); } 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) ((struct ufs1_dinode *)iobuf)[ino_to_fsbo(&sblock, ino)] = ip->dp1; diff --git a/sbin/newfs/newfs.8 b/sbin/newfs/newfs.8 index 8771188f18a1..6dcb8592b9e1 100644 --- a/sbin/newfs/newfs.8 +++ b/sbin/newfs/newfs.8 @@ -52,6 +52,7 @@ .Op Fl i Ar bytes .Op Fl m Ar free-space .Op Fl o Ar optimization +.Op Fl p Ar partition .Op Fl r Ar reserved .Op Fl s Ar size .Ar special @@ -201,6 +202,17 @@ the default is to optimize for See .Xr tunefs 8 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 The size, in sectors, of reserved space at the end of the partition specified in diff --git a/sbin/newfs/newfs.c b/sbin/newfs/newfs.c index d5fb66d8346d..269707b5e43f 100644 --- a/sbin/newfs/newfs.c +++ b/sbin/newfs/newfs.c @@ -139,6 +139,9 @@ u_char *volumelabel = NULL; /* volume label for filesystem */ struct uufsd disk; /* libufs disk structure */ 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 int unlabeled; @@ -147,6 +150,18 @@ static struct disklabel *getdisklabel(char *s); static void rewritelabel(char *s, struct disklabel *lp); 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 main(int argc, char *argv[]) { @@ -158,7 +173,9 @@ main(int argc, char *argv[]) intmax_t reserved; int ch, i; off_t mediasize; + char part_name; /* partition name, default to full disk */ + part_name = 'c'; reserved = 0; while ((ch = getopt(argc, argv, "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) errx(1, "%s: bad reserved size", optarg); break; + case 'p': + is_file = 1; + part_name = optarg[0]; + break; + case 's': errno = 0; fssize = strtoimax(optarg, &cp, 0); @@ -294,6 +316,8 @@ main(int argc, char *argv[]) usage(); special = argv[0]; + if (!special[0]) + err(1, "empty file/special name"); cp = strrchr(special, '/'); if (cp == 0) { /* @@ -303,7 +327,16 @@ main(int argc, char *argv[]) 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)) { if (disk.d_error != NULL) errx(1, "%s: %s", special, disk.d_error); @@ -312,22 +345,30 @@ main(int argc, char *argv[]) } if (fstat(disk.d_fd, &st) < 0) err(1, "%s", special); - if ((st.st_mode & S_IFMT) != S_IFCHR) - errx(1, "%s: not a character-special device", special); + if ((st.st_mode & S_IFMT) != S_IFCHR) { + 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) - sectorsize = 0; /* back out on error for safety */ - if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize) != -1) + sectorsize = 0; /* back out on error for safety */ + if (sectorsize && ioctl(disk.d_fd, DIOCGMEDIASIZE, &mediasize) != -1) getfssize(&fssize, special, mediasize / sectorsize, reserved); + } pp = NULL; lp = getdisklabel(special); if (lp != NULL) { - cp = strchr(special, '\0'); - cp--; - if ((*cp < 'a' || *cp > 'h') && !isdigit(*cp)) - errx(1, "%s: can't figure out file system partition", - special); + cp = &part_name; if (isdigit(*cp)) pp = &lp->d_partitions[RAW_PART]; else @@ -346,6 +387,8 @@ main(int argc, char *argv[]) fsize = pp->p_fsize; if (bsize == 0) bsize = pp->p_frag * pp->p_fsize; + if (is_file) + part_ofs = pp->p_offset; } if (sectorsize <= 0) errx(1, "%s: no default sector size", special); @@ -414,6 +457,19 @@ getdisklabel(char *s) static struct disklabel lab; 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) return (&lab); unlabeled++; @@ -432,6 +488,14 @@ rewritelabel(char *s, struct disklabel *lp) return; lp->d_checksum = 0; 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) 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-m minimum free space %%\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-s file system size (sectors)\n"); exit(1); diff --git a/sbin/newfs/newfs.h b/sbin/newfs/newfs.h index 5c428c412ecf..0d7cb62379dc 100644 --- a/sbin/newfs/newfs.h +++ b/sbin/newfs/newfs.h @@ -70,4 +70,20 @@ extern int avgfilesperdir; /* expected number of files per directory */ extern u_char *volumelabel; /* volume label for filesystem */ 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 *);