From 8c4b3f0afd38c982ffa910b7736796cd33d24389 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Wed, 20 Jan 2021 17:03:21 -0800 Subject: Update to upstream 6424881cc82a65a833fc6fb79730474caedf6222. Test: treehugger Change-Id: Ib11457ec6d166e774c9a053e23db4131c0030321 --- Android.bp | 5 +- METADATA | 6 +- freebsd-compat.h | 42 +++++++++++++ mkfs_msdos.c | 181 +++++++++++++++++++++++++++++++++++++++++-------------- mkfs_msdos.h | 7 +-- newfs_msdos.c | 15 +++-- 6 files changed, 192 insertions(+), 64 deletions(-) create mode 100644 freebsd-compat.h diff --git a/Android.bp b/Android.bp index fcaffbc..a447263 100755 --- a/Android.bp +++ b/Android.bp @@ -1,5 +1,6 @@ cc_binary { name: "newfs_msdos", + c_std: "gnu11", cflags: [ "-Wall", "-Werror", @@ -7,9 +8,7 @@ cc_binary { "-Wno-unused-parameter", "-Wno-unused-variable", "-D_FILE_OFFSET_BITS=64", - "-D_GNU_SOURCE", - "-DSIGINFO=SIGUSR2", - "-Dnitems(x)=(sizeof((x))/sizeof((x)[0]))", + "-include freebsd-compat.h" ], srcs: [ "mkfs_msdos.c", diff --git a/METADATA b/METADATA index a0b9090..af1cf5d 100644 --- a/METADATA +++ b/METADATA @@ -9,9 +9,9 @@ third_party { } url { type: ARCHIVE - value: "https://github.git.corp.google.com/freebsd/freebsd/+archive/b25a2bc/sbin/newfs_msdos.tar.gz" + value: "https://github.git.corp.google.com/freebsd/freebsd/+archive/6424881cc82a65a833fc6fb79730474caedf6222/sbin/newfs_msdos.tar.gz" } - version: "b25a2bc" - last_upgrade_date { year: 2018 month: 4 day: 26 } + version: "6424881cc82a65a833fc6fb79730474caedf6222" + last_upgrade_date { year: 2021 month: 1 day: 20 } license_type: NOTICE } diff --git a/freebsd-compat.h b/freebsd-compat.h new file mode 100644 index 0000000..5e39c5a --- /dev/null +++ b/freebsd-compat.h @@ -0,0 +1,42 @@ +#pragma once + +#define _GNU_SOURCE + +#include + +#include +// Ensure we use a BSD powerof2 that works in static_assert (unlike glibc's). +#undef powerof2 +#define powerof2(x) ((((x)-1)&(x))==0) +// This is in BSD's . +#define nitems(x) (sizeof((x))/sizeof((x)[0])) + +// This is used as the size of the write buffer of sectors. +#define MAXPHYS (1024 * 1024) + +//#define static_assert _Static_assert + +// TODO: do we actually want this, or should we live without? +#define SIGINFO SIGUSR2 + + +// On glibc, these headers use `__unused` as an identifier, so drag them in +// first. +#include +#if __has_include() +#include +#endif +// Bionic, like the BSDs, has __unused. glibc doesn't. +#if defined(__GLIBC__) +#define __unused __attribute__((__unused__)) +#endif +// Neither macOS nor glibc has __packed. +#if defined(__APPLE__) || defined(__GLIBC__) +#define __packed __attribute__((__packed__)) +#endif + +// The BSDs (including Android and macOS) have getprogname(), but glibc doesn't. +#if defined(__GLIBC__) +#include +static inline char* getprogname() { return program_invocation_short_name; } +#endif diff --git a/mkfs_msdos.c b/mkfs_msdos.c index 878ff8f..667df47 100644 --- a/mkfs_msdos.c +++ b/mkfs_msdos.c @@ -27,11 +27,14 @@ #ifndef lint static const char rcsid[] = - "$FreeBSD: head/sbin/newfs_msdos/mkfs_msdos.c 335189 2018-06-15 06:03:40Z delphij $"; + "$FreeBSD$"; #endif /* not lint */ #include -#if defined(__linux__) +#ifdef MAKEFS +/* In the makefs case we only want struct disklabel */ +#include +#elif defined(__linux__) #include #include #include @@ -44,8 +47,12 @@ static const char rcsid[] = #include #endif #include +#if __has_include() +#include +#endif #include +#include #include #include #include @@ -61,19 +68,13 @@ static const char rcsid[] = #include "mkfs_msdos.h" -#if !defined(__packed) -#define __packed __attribute__((__packed__)) -#endif -#if !defined(__unused) -#define __unused __attribute__((__unused__)) -#endif - #define MAXU16 0xffff /* maximum unsigned 16-bit quantity */ #define BPN 4 /* bits per nibble */ #define NPB 2 /* nibbles per byte */ #define DOSMAGIC 0xaa55 /* DOS magic number */ #define MINBPS 512 /* minimum bytes per sector */ +#define MAXBPS 4096 /* maximum bytes per sector */ #define MAXSPC 128 /* maximum sectors per cluster */ #define MAXNFT 16 /* maximum number of FATs */ #define DEFBLK 4096 /* default block size */ @@ -230,6 +231,7 @@ static volatile sig_atomic_t got_siginfo; static void infohandler(int); static int check_mounted(const char *, mode_t); +static ssize_t getchunksize(void); static int getstdfmt(const char *, struct bpb *); static int getdiskinfo(int, const char *, const char *, int, struct bpb *); static void print_bpb(struct bpb *); @@ -253,6 +255,7 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) struct bsx *bsx; struct de *de; u_int8_t *img; + u_int8_t *physbuf, *physbuf_end; const char *bname; ssize_t n; time_t now; @@ -261,8 +264,9 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) bool set_res, set_spf, set_spc; int fd, fd1, rv; struct msdos_options o = *op; + ssize_t chunksize; - img = NULL; + physbuf = NULL; rv = -1; fd = fd1 = -1; @@ -300,12 +304,18 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) if (!S_ISREG(sb.st_mode)) warnx("warning, %s is not a regular file", fname); } else { +#ifdef MAKEFS + errx(1, "o.create_size must be set!"); +#else if (!S_ISCHR(sb.st_mode)) warnx("warning, %s is not a character device", fname); +#endif } +#ifndef MAKEFS if (!o.no_create) if (check_mounted(fname, sb.st_mode) == -1) goto done; +#endif if (o.offset && o.offset != lseek(fd, o.offset, SEEK_SET)) { warnx("cannot seek to %jd", (intmax_t)o.offset); goto done; @@ -331,7 +341,8 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) bpb.bpbHiddenSecs = o.hidden_sectors; if (!(o.floppy || (o.drive_heads && o.sectors_per_track && o.bytes_per_sector && o.size && o.hidden_sectors_set))) { - getdiskinfo(fd, fname, dtype, o.hidden_sectors_set, &bpb); + if (getdiskinfo(fd, fname, dtype, o.hidden_sectors_set, &bpb) == -1) + goto done; bpb.bpbHugeSectors -= (o.offset / bpb.bpbBytesPerSec); if (bpb.bpbSecPerClust == 0) { /* set defaults */ if (bpb.bpbHugeSectors <= 6000) /* about 3MB -> 512 bytes */ @@ -346,13 +357,11 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) bpb.bpbSecPerClust = 64; /* otherwise 32k */ } } - if (!powerof2(bpb.bpbBytesPerSec)) { - warnx("bytes/sector (%u) is not a power of 2", bpb.bpbBytesPerSec); - goto done; - } - if (bpb.bpbBytesPerSec < MINBPS) { - warnx("bytes/sector (%u) is too small; minimum is %u", - bpb.bpbBytesPerSec, MINBPS); + if (bpb.bpbBytesPerSec < MINBPS || + bpb.bpbBytesPerSec > MAXBPS || + !powerof2(bpb.bpbBytesPerSec)) { + warnx("Invalid bytes/sector (%u): must be 512, 1024, 2048 or 4096", + bpb.bpbBytesPerSec); goto done; } @@ -436,10 +445,7 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) bname = o.bootstrap; if (!strchr(bname, '/')) { snprintf(buf, sizeof(buf), "/boot/%s", bname); - if (!(bname = strdup(buf))) { - warn(NULL); - goto done; - } + bname = buf; } if ((fd1 = open(bname, O_RDONLY)) == -1 || fstat(fd1, &sb)) { warn("%s", bname); @@ -627,19 +633,25 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) tm = localtime(&now); } - - if (!(img = malloc(bpb.bpbBytesPerSec))) { + chunksize = getchunksize(); + physbuf = malloc(chunksize); + if (physbuf == NULL) { warn(NULL); goto done; } + physbuf_end = physbuf + chunksize; + img = physbuf; + dir = bpb.bpbResSectors + (bpb.bpbFATsecs ? bpb.bpbFATsecs : bpb.bpbBigFATsecs) * bpb.bpbFATs; memset(&si_sa, 0, sizeof(si_sa)); si_sa.sa_handler = infohandler; +#ifdef SIGINFO if (sigaction(SIGINFO, &si_sa, NULL) == -1) { warn("sigaction SIGINFO"); goto done; } +#endif #if defined(__linux__) if (ioctl(fd, BLKBSZSET, &bpb.bpbBytesPerSec)) @@ -738,7 +750,7 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) mk4(img, 0x41615252); mk4(img + MINBPS - 28, 0x61417272); mk4(img + MINBPS - 24, 0xffffffff); - mk4(img + MINBPS - 20, bpb.bpbRootClust); + mk4(img + MINBPS - 20, 0xffffffff); mk2(img + MINBPS - 2, DOSMAGIC); } else if (lsn >= bpb.bpbResSectors && lsn < dir && !((lsn - bpb.bpbResSectors) % @@ -760,19 +772,37 @@ mkfs_msdos(const char *fname, const char *dtype, const struct msdos_options *op) (u_int)tm->tm_mday; mk2(de->deMDate, x); } - if ((n = write(fd, img, bpb.bpbBytesPerSec)) == -1) { - warn("%s", fname); - goto done; - } - if ((unsigned)n != bpb.bpbBytesPerSec) { - warnx("%s: can't write sector %u", fname, lsn); - goto done; + /* + * Issue a write of chunksize once we have collected + * enough sectors. + */ + img += bpb.bpbBytesPerSec; + if (img >= physbuf_end) { + n = write(fd, physbuf, chunksize); + if (n != chunksize) { + warnx("%s: can't write sector %u", fname, lsn); + goto done; + } + img = physbuf; } } + /* + * Write remaining sectors, if the last write didn't end + * up filling a whole chunk. + */ + if (img != physbuf) { + ssize_t tailsize = img - physbuf; + + n = write(fd, physbuf, tailsize); + if (n != tailsize) { + warnx("%s: can't write sector %u", fname, lsn); + goto done; + } + } } rv = 0; done: - free(img); + free(physbuf); if (fd != -1) close(fd); if (fd1 != -1) @@ -787,7 +817,11 @@ done: static int check_mounted(const char *fname, mode_t mode) { -#if 0 +/* + * If getmntinfo() is not available (e.g. Linux) don't check. This should + * not be a problem since we will only be using makefs to create images. + */ +#if 0 && !defined(MAKEFS) struct statfs *mp; const char *s1, *s2; size_t len; @@ -816,6 +850,47 @@ check_mounted(const char *fname, mode_t mode) return 0; } +/* + * Get optimal I/O size + */ +static ssize_t +getchunksize(void) +{ + static int chunksize; + + if (chunksize != 0) + return ((ssize_t)chunksize); + +#ifdef KERN_MAXPHYS + int mib[2]; + size_t len; + + mib[0] = CTL_KERN; + mib[1] = KERN_MAXPHYS; + len = sizeof(chunksize); + + if (sysctl(mib, 2, &chunksize, &len, NULL, 0) == -1) { + warn("sysctl: KERN_MAXPHYS, using %zu", (size_t)MAXPHYS); + chunksize = 0; + } +#endif + if (chunksize == 0) + chunksize = MAXPHYS; + + /* + * For better performance, we want to write larger chunks instead of + * individual sectors (the size can only be 512, 1024, 2048 or 4096 + * bytes). Assert that chunksize can always hold an integer number of + * sectors by asserting that both are power of two numbers and the + * chunksize is greater than MAXBPS. + */ + static_assert(powerof2(MAXBPS), "MAXBPS is not power of 2"); + assert(powerof2(chunksize)); + assert(chunksize > MAXBPS); + + return ((ssize_t)chunksize); +} + /* * Get a standard format. */ @@ -834,6 +909,25 @@ getstdfmt(const char *fmt, struct bpb *bpb) return 0; } +#if 0 +static void +compute_geometry_from_file(int fd, const char *fname, struct disklabel *lp) +{ + struct stat st; + off_t ms; + + if (fstat(fd, &st)) + err(1, "cannot get disk size"); + if (!S_ISREG(st.st_mode)) + errx(1, "%s is not a regular file", fname); + ms = st.st_size; + lp->d_secsize = 512; + lp->d_nsectors = 63; + lp->d_ntracks = 255; + lp->d_secperunit = ms / lp->d_secsize; +} +#endif + /* * Get disk slice, partition, and geometry information. */ @@ -879,8 +973,10 @@ getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, struct bpb *bpb) { struct disklabel *lp, dlp; + off_t hs = 0; +#ifndef MAKEFS + off_t ms; struct fd_type type; - off_t ms, hs = 0; lp = NULL; @@ -892,16 +988,8 @@ getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, /* Maybe it's a floppy drive */ if (lp == NULL) { if (ioctl(fd, DIOCGMEDIASIZE, &ms) == -1) { - struct stat st; - - if (fstat(fd, &st)) - err(1, "cannot get disk size"); /* create a fake geometry for a file image */ - ms = st.st_size; - dlp.d_secsize = 512; - dlp.d_nsectors = 63; - dlp.d_ntracks = 255; - dlp.d_secperunit = ms / dlp.d_secsize; + compute_geometry_from_file(fd, fname, &dlp); lp = &dlp; } else if (ioctl(fd, FD_GTYPE, &type) != -1) { dlp.d_secsize = 128 << type.secsize; @@ -941,6 +1029,11 @@ getdiskinfo(int fd, const char *fname, const char *dtype, __unused int oflag, hs = (ms / dlp.d_secsize) - dlp.d_secperunit; lp = &dlp; } +#else + /* In the makefs case we only support image files: */ + compute_geometry_from_file(fd, fname, &dlp); + lp = &dlp; +#endif if (bpb->bpbBytesPerSec == 0) { if (ckgeom(fname, lp->d_secsize, "bytes/sector") == -1) diff --git a/mkfs_msdos.h b/mkfs_msdos.h index b49a577..7e0c662 100644 --- a/mkfs_msdos.h +++ b/mkfs_msdos.h @@ -1,4 +1,4 @@ -/* $FreeBSD: head/sbin/newfs_msdos/mkfs_msdos.h 335189 2018-06-15 06:03:40Z delphij $ */ +/* $FreeBSD$ */ /* $NetBSD: mkfs_msdos.h,v 1.3 2015/10/16 17:38:17 christos Exp $ */ /*- @@ -32,7 +32,6 @@ #include #include -#include #define ALLOPTS \ AOPT('@', off_t, offset, 0, "Offset in device") \ AOPT('A', bool, align, -2, "Attempt to cluster align root directory") \ @@ -71,7 +70,3 @@ ALLOPTS }; int mkfs_msdos(const char *, const char *, const struct msdos_options *); - -#if defined(__GLIBC__) -static inline char* getprogname() { return program_invocation_short_name; } -#endif diff --git a/newfs_msdos.c b/newfs_msdos.c index cd03164..bac250e 100644 --- a/newfs_msdos.c +++ b/newfs_msdos.c @@ -29,7 +29,7 @@ #ifndef lint static const char rcsid[] = - "$FreeBSD: head/sbin/newfs_msdos/newfs_msdos.c 335189 2018-06-15 06:03:40Z delphij $"; + "$FreeBSD$"; #endif /* not lint */ #include @@ -178,18 +178,17 @@ main(int argc, char *argv[]) argv += optind; if (argc < 1 || argc > 2) usage(); - if (o.align) { - if (o.hidden_sectors_set) - errx(1, "align (-A) is incompatible with -r"); - } + if (o.align) { + if (o.reserved_sectors) + errx(1, "align (-A) is incompatible with -r"); + } fname = *argv++; if (!o.create_size && !strchr(fname, '/')) { snprintf(buf, sizeof(buf), "%s%s", _PATH_DEV, fname); - if (!(fname = strdup(buf))) - err(1, NULL); + fname = buf; } dtype = *argv; - return !!mkfs_msdos(fname, dtype, &o); + exit(!!mkfs_msdos(fname, dtype, &o)); } /* -- cgit v1.2.3