#define FS_MAX (((diskaddr_t)INT_MAX) * (MAXBSIZE/DEV_BSIZE))
#define DFLNSECT 32
#define DFLNTRAK 16
#define DEF_SECTORS_EFI 128
#define DEF_TRACKS_EFI 48
#define DESCPG 16
#define DESBLKSIZE 8192
#define DESFRAGSIZE 1024
#define MINFREE 10
#define DEFAULTOPT FS_OPTTIME
#define ROTDELAY 0
#define MAXBLKPG(bsize) ((bsize) / sizeof (daddr32_t))
#define NBPI 2048
#define MTB_NBPI (MB)
#define DEFHZ 60
#define NRPOS 8
#ifdef DEBUG
#define dbgprintf(x) printf x
#else
#define dbgprintf(x)
#endif
#define tprintf(x) if (Nflag && retry) \
(void) strncat(tmpbuf, x, strlen(x)); \
else \
(void) fprintf(stderr, x);
#define ALTSB 32
#define RC_DEFAULT 0
#define RC_KEYWORD 1
#define RC_POSITIONAL 2
#define UFS_HOLE -1
#ifndef STANDALONE
#include <stdio.h>
#include <sys/mnttab.h>
#endif
#include <stdlib.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <errno.h>
#include <sys/param.h>
#include <time.h>
#include <sys/types.h>
#include <sys/sysmacros.h>
#include <sys/vnode.h>
#include <sys/fs/ufs_fsdir.h>
#include <sys/fs/ufs_inode.h>
#include <sys/fs/ufs_fs.h>
#include <sys/fs/ufs_log.h>
#include <sys/mntent.h>
#include <sys/filio.h>
#include <limits.h>
#include <sys/int_const.h>
#include <signal.h>
#include <sys/efi_partition.h>
#include <fslib.h>
#include "roll_log.h"
#define bcopy(f, t, n) (void) memcpy(t, f, n)
#define bzero(s, n) (void) memset(s, 0, n)
#define bcmp(s, d, n) memcmp(s, d, n)
#define index(s, r) strchr(s, r)
#define rindex(s, r) strrchr(s, r)
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <locale.h>
#include <fcntl.h>
#include <sys/isa_defs.h>
#include <sys/vtoc.h>
#include <sys/dkio.h>
#include <sys/asynch.h>
extern offset_t llseek();
extern char *getfullblkname();
extern long lrand48();
extern int optind;
extern char *optarg;
#define CGSIZE(fs) \
(sizeof (struct cg) + \
(fs)->fs_cpg * sizeof (long) + \
(fs)->fs_cpg * (fs)->fs_nrpos * sizeof (short) + \
howmany((fs)->fs_ipg, NBBY) + \
howmany((fs)->fs_cpg * (fs)->fs_spc / NSPF(fs), NBBY))
#define MAXIpG(fs) roundup((fs)->fs_bsize * NBBY / 3, INOPB(fs))
#define MAXIpG_B(b, d) roundup((b) * NBBY / (d), (b) / sizeof (struct dinode))
#define UMASK 0755
#define MAXINOPB (MAXBSIZE / sizeof (struct dinode))
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
#define MB (1024*1024)
#define BETWEEN(x, l, h) ((x) >= (l) && (x) <= (h))
#define IRANDOMIZE(icp) (icp)->ic_gen = lrand48();
#define ALLOW_PERCENT 0x01
#define ALLOW_MS1 0x02
#define ALLOW_MS2 0x04
#define ALLOW_END_ONLY 0x08
#define MAXAIO 1000
#define BLOCK 1
#define NOBLOCK 0
#define RELEASE 1
#define SAVE 0
typedef struct aio_trans {
aio_result_t resultbuf;
diskaddr_t bno;
char *buffer;
int size;
int release;
struct aio_trans *next;
} aio_trans;
typedef struct aio_results {
int max;
int outstanding;
int maxpend;
aio_trans *trans;
} aio_results;
int aio_inited = 0;
aio_results results;
#define MAXBUF 20
#define MAXBUFMEM (8 * 1024 * 1024)
typedef struct bufhdr {
struct bufhdr *head;
struct bufhdr *next;
} bufhdr;
int bufhdrsize;
bufhdr inodebuf = { NULL, NULL };
bufhdr cgsumbuf = { NULL, NULL };
#define SECTORS_PER_TERABYTE (1LL << 31)
#define FS_SIZE_UPPER_LIMIT 0x100000000000LL
static char *getbuf(bufhdr *bufhead, int size);
static void freebuf(char *buf);
static void freetrans(aio_trans *transp);
static aio_trans *get_aiop();
static aio_trans *wait_for_write(int block);
static void initcg(int cylno);
static void fsinit();
static int makedir(struct direct *protodir, int entries);
static void iput(struct inode *ip);
static void rdfs(diskaddr_t bno, int size, char *bf);
static void wtfs(diskaddr_t bno, int size, char *bf);
static void awtfs(diskaddr_t bno, int size, char *bf, int release);
static void wtfs_breakup(diskaddr_t bno, int size, char *bf);
static int isblock(struct fs *fs, unsigned char *cp, int h);
static void clrblock(struct fs *fs, unsigned char *cp, int h);
static void setblock(struct fs *fs, unsigned char *cp, int h);
static void usage(void) __NORETURN;
static void dump_fscmd(char *fsys, int fsi);
static uint64_t number(uint64_t d_value, char *param, int flags);
static int match(char *s);
static char checkopt(char *optim);
static char checkmtb(char *mtbarg);
static void range_check(long *varp, char *name, long minimum,
long maximum, long def_val, int user_supplied);
static void range_check_64(uint64_t *varp, char *name, uint64_t minimum,
uint64_t maximum, uint64_t def_val, int user_supplied);
static daddr32_t alloc(int size, int mode);
static diskaddr_t get_max_size(int fd);
static long get_max_track_size(int fd);
static void block_sigint(sigset_t *old_mask);
static void unblock_sigint(sigset_t *old_mask);
static void recover_from_sigint(int signum);
static int confirm_abort(void);
static int getaline(FILE *fp, char *loc, int maxlen);
static void flush_writes(void);
static long compute_maxcpg(long, long, long, long, long);
static int in_64bit_mode(void);
static int validate_size(int fd, diskaddr_t size);
static void dump_sblock(void);
#define XMIT_2_X_ALIGN 8
#pragma align XMIT_2_X_ALIGN(fsun, altfsun, cgun)
union {
struct fs fs;
char pad[SBSIZE];
} fsun, altfsun;
#define sblock fsun.fs
#define altsblock altfsun.fs
struct csum *fscs;
union cgun {
struct cg cg;
char pad[MAXBSIZE];
} cgun;
#define acg cgun.cg
#define WIDTH 80
struct dinode zino[MAXBSIZE / sizeof (struct dinode)];
int fsi = -1;
int fso = -1;
#define BIG 0x7fffffffffffffffLL
#define NO_DEFAULT LONG_MIN
#define INVALIDSBLIMIT 10
long sectorsize = DEV_BSIZE;
long bbsize = BBSIZE;
long sbsize = SBSIZE;
diskaddr_t fssize_db;
diskaddr_t fssize_frag;
long cpg;
int cpg_flag = RC_DEFAULT;
long rotdelay = -1;
int rotdelay_flag = RC_DEFAULT;
long maxcontig;
int maxcontig_flag = RC_DEFAULT;
long nsect = DFLNSECT;
int nsect_flag = RC_DEFAULT;
long ntrack = DFLNTRAK;
int ntrack_flag = RC_DEFAULT;
long bsize = DESBLKSIZE;
int bsize_flag = RC_DEFAULT;
long fragsize = DESFRAGSIZE;
int fragsize_flag = RC_DEFAULT;
long minfree = MINFREE;
int minfree_flag = RC_DEFAULT;
long rps = DEFHZ;
int rps_flag = RC_DEFAULT;
long nbpi = NBPI;
int nbpi_flag = RC_DEFAULT;
long nrpos = NRPOS;
int nrpos_flag = RC_DEFAULT;
long apc = 0;
int apc_flag = RC_DEFAULT;
char opt = 't';
char mtb = 'n';
#define DEFAULT_SECT_TRAK_CPG (nsect_flag == RC_DEFAULT && \
ntrack_flag == RC_DEFAULT && \
cpg_flag == RC_DEFAULT)
long debug = 0;
int spc_flag = 0;
int Nflag;
int mflag;
int rflag;
int Rflag;
char *fsys;
time_t mkfstime;
char *string;
int label_type;
int islog;
int islogok;
int waslog;
#define NOTENOUGHSPACE 33
int grow;
#define GROW_WITH_DEFAULT_TRAK (grow && ntrack_flag == RC_DEFAULT)
static int Pflag;
int ismounted;
char *directory;
diskaddr_t grow_fssize;
long grow_fs_size;
long grow_fs_ncg;
diskaddr_t grow_fs_csaddr;
long grow_fs_cssize;
int grow_fs_clean;
struct csum *grow_fscs;
diskaddr_t grow_sifrag;
int test;
int testforce;
diskaddr_t testfrags;
int inlockexit;
int isbad;
void lockexit(int) __NORETURN;
void randomgeneration(void);
void checksummarysize(void);
int checksblock(struct fs, int);
void growinit(char *);
void checkdev(char *, char *);
void checkmount(struct mnttab *, char *);
struct dinode *gdinode(ino_t);
int csfraginrange(daddr32_t);
struct csfrag *findcsfrag(daddr32_t, struct csfrag **);
void checkindirect(ino_t, daddr32_t *, daddr32_t, int);
void addcsfrag(ino_t, daddr32_t, struct csfrag **);
void delcsfrag(daddr32_t, struct csfrag **);
void checkdirect(ino_t, daddr32_t *, daddr32_t *, int);
void findcsfragino(void);
void fixindirect(daddr32_t, int);
void fixdirect(caddr_t, daddr32_t, daddr32_t *, int);
void fixcsfragino(void);
void extendsummaryinfo(void);
int notenoughspace(void);
void unalloccsfragino(void);
void unalloccsfragfree(void);
void findcsfragfree(void);
void copycsfragino(void);
void rdcg(long);
void wtcg(void);
void flcg(void);
void allocfrags(long, daddr32_t *, long *);
void alloccsfragino(void);
void alloccsfragfree(void);
void freefrags(daddr32_t, long, long);
int findfreerange(long *, long *);
void resetallocinfo(void);
void extendcg(long);
void ulockfs(void);
void wlockfs(void);
void clockfs(void);
void wtsb(void);
static int64_t checkfragallocated(daddr32_t);
static struct csum *read_summaryinfo(struct fs *);
static diskaddr_t probe_summaryinfo();
int
main(int argc, char *argv[])
{
long i, mincpc, mincpg, ibpcl;
long cylno, rpos, blk, j, warn = 0;
long mincpgcnt, maxcpg;
uint64_t used, bpcg, inospercg;
long mapcramped, inodecramped;
long postblsize, rotblsize, totalsbsize;
FILE *mnttab;
struct mnttab mntp;
char *special;
struct statvfs64 fs;
struct dk_geom dkg;
struct dk_minfo dkminfo;
char pbuf[sizeof (uint64_t) * 3 + 1];
char *tmpbuf;
int width, plen;
uint64_t num;
int c, saverr;
diskaddr_t max_fssize;
long tmpmaxcontig = -1;
struct sigaction sigact;
uint64_t nbytes64;
int remaining_cg;
int do_dot = 0;
int use_efi_dflts = 0, retry = 0, isremovable = 0, ishotpluggable = 0;
int invalid_sb_cnt, ret, skip_this_sb, cg_too_small;
int geom_nsect, geom_ntrack, geom_cpg;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
while ((c = getopt(argc, argv, "F:bmo:VPGM:T:t:")) != EOF) {
switch (c) {
case 'F':
string = optarg;
if (strcmp(string, "ufs") != 0)
usage();
break;
case 'm':
mflag++;
break;
case 'o':
string = optarg;
while (*string != '\0') {
if (match("nsect=")) {
nsect = number(DFLNSECT, "nsect", 0);
nsect_flag = RC_KEYWORD;
} else if (match("ntrack=")) {
ntrack = number(DFLNTRAK, "ntrack", 0);
ntrack_flag = RC_KEYWORD;
} else if (match("bsize=")) {
bsize = number(DESBLKSIZE, "bsize", 0);
bsize_flag = RC_KEYWORD;
} else if (match("fragsize=")) {
fragsize = number(DESFRAGSIZE,
"fragsize", 0);
fragsize_flag = RC_KEYWORD;
} else if (match("cgsize=")) {
cpg = number(DESCPG, "cgsize", 0);
cpg_flag = RC_KEYWORD;
} else if (match("free=")) {
minfree = number(MINFREE, "free",
ALLOW_PERCENT);
minfree_flag = RC_KEYWORD;
} else if (match("maxcontig=")) {
tmpmaxcontig =
number(-1, "maxcontig", 0);
maxcontig_flag = RC_KEYWORD;
} else if (match("nrpos=")) {
nrpos = number(NRPOS, "nrpos", 0);
nrpos_flag = RC_KEYWORD;
} else if (match("rps=")) {
rps = number(DEFHZ, "rps", 0);
rps_flag = RC_KEYWORD;
} else if (match("nbpi=")) {
nbpi = number(NBPI, "nbpi", 0);
nbpi_flag = RC_KEYWORD;
} else if (match("opt=")) {
opt = checkopt(string);
} else if (match("mtb=")) {
mtb = checkmtb(string);
} else if (match("apc=")) {
apc = number(0, "apc", 0);
apc_flag = RC_KEYWORD;
} else if (match("gap=")) {
(void) number(0, "gap", ALLOW_MS1);
rotdelay = ROTDELAY;
rotdelay_flag = RC_DEFAULT;
} else if (match("debug=")) {
debug = number(0, "debug", 0);
} else if (match("N")) {
Nflag++;
} else if (match("calcsb")) {
rflag++;
Nflag++;
} else if (match("calcbinsb")) {
rflag++;
Rflag++;
Nflag++;
} else if (*string == '\0') {
break;
} else {
(void) fprintf(stderr, gettext(
"illegal option: %s\n"), string);
usage();
}
if (*string == ',') string++;
if (*string == ' ') string++;
}
break;
case 'V':
{
char *opt_text;
int opt_count;
(void) fprintf(stdout, gettext("mkfs -F ufs "));
for (opt_count = 1; opt_count < argc;
opt_count++) {
opt_text = argv[opt_count];
if (opt_text)
(void) fprintf(stdout, " %s ",
opt_text);
}
(void) fprintf(stdout, "\n");
}
break;
case 'b':
break;
case 'M':
directory = optarg;
case 'G':
grow = 1;
break;
case 'P':
Pflag = 1;
grow = 1;
break;
case 'T':
testforce = 1;
case 't':
test = 1;
string = optarg;
testfrags = number(NO_DEFAULT, "testfrags", 0);
break;
case '?':
usage();
break;
}
}
#ifdef MKFS_DEBUG
mkfstime = 0;
#else
(void) time(&mkfstime);
#endif
if (optind >= (argc - 1)) {
if (optind > (argc - 1)) {
(void) fprintf(stderr,
gettext("special not specified\n"));
usage();
} else if (mflag == 0) {
(void) fprintf(stderr,
gettext("size not specified\n"));
usage();
}
}
argc -= optind;
argv = &argv[optind];
fsys = argv[0];
fsi = open64(fsys, O_RDONLY);
if (fsi < 0) {
(void) fprintf(stderr, gettext("%s: cannot open\n"), fsys);
lockexit(32);
}
if (mflag) {
dump_fscmd(fsys, fsi);
lockexit(0);
}
max_fssize = get_max_size(fsi);
switch (argc - 1) {
default:
usage();
case 15:
mtb = checkmtb(argv[15]);
case 14:
string = argv[14];
tmpmaxcontig = number(-1, "maxcontig", 0);
maxcontig_flag = RC_POSITIONAL;
case 13:
string = argv[13];
nrpos = number(NRPOS, "nrpos", 0);
nrpos_flag = RC_POSITIONAL;
case 12:
string = argv[12];
rotdelay = ROTDELAY;
rotdelay_flag = RC_DEFAULT;
case 11:
string = argv[11];
apc = number(0, "apc", 0);
apc_flag = RC_POSITIONAL;
case 10:
opt = checkopt(argv[10]);
case 9:
string = argv[9];
nbpi = number(NBPI, "nbpi", 0);
nbpi_flag = RC_POSITIONAL;
case 8:
string = argv[8];
rps = number(DEFHZ, "rps", 0);
rps_flag = RC_POSITIONAL;
case 7:
string = argv[7];
minfree = number(MINFREE, "free", ALLOW_PERCENT);
minfree_flag = RC_POSITIONAL;
case 6:
string = argv[6];
cpg = number(DESCPG, "cgsize", 0);
cpg_flag = RC_POSITIONAL;
case 5:
string = argv[5];
fragsize = number(DESFRAGSIZE, "fragsize", 0);
fragsize_flag = RC_POSITIONAL;
case 4:
string = argv[4];
bsize = number(DESBLKSIZE, "bsize", 0);
bsize_flag = RC_POSITIONAL;
case 3:
string = argv[3];
ntrack = number(DFLNTRAK, "ntrack", 0);
ntrack_flag = RC_POSITIONAL;
case 2:
string = argv[2];
nsect = number(DFLNSECT, "nsect", 0);
nsect_flag = RC_POSITIONAL;
case 1:
string = argv[1];
fssize_db = number(max_fssize, "size", 0);
}
if (label_type == LABEL_TYPE_EFI) {
if (apc_flag == RC_DEFAULT) apc = 0;
if (nrpos_flag == RC_DEFAULT) nrpos = 1;
if (ntrack_flag == RC_DEFAULT) ntrack = DEF_TRACKS_EFI;
if (rps_flag == RC_DEFAULT) rps = DEFHZ;
if (nsect_flag == RC_DEFAULT) nsect = DEF_SECTORS_EFI;
}
if ((maxcontig_flag == RC_DEFAULT) || (tmpmaxcontig == -1) ||
(maxcontig == -1)) {
long maxtrax = get_max_track_size(fsi);
maxcontig = maxtrax / bsize;
} else {
maxcontig = tmpmaxcontig;
}
dbgprintf(("DeBuG maxcontig : %ld\n", maxcontig));
if (rotdelay == -1) {
rotdelay = ROTDELAY;
}
if (cpg_flag == RC_DEFAULT) {
cpg = DESCPG;
}
dbgprintf(("DeBuG cpg : %ld\n", cpg));
range_check(&bsize, "bsize", MINBSIZE, MAXBSIZE, DESBLKSIZE,
bsize_flag);
if (!POWEROF2(bsize)) {
(void) fprintf(stderr,
gettext("block size must be a power of 2, not %ld\n"),
bsize);
bsize = DESBLKSIZE;
(void) fprintf(stderr,
gettext("mkfs: bsize reset to default %ld\n"),
bsize);
}
if (fssize_db > max_fssize && validate_size(fsi, fssize_db)) {
(void) fprintf(stderr, gettext(
"Warning: the requested size of this file system\n"
"(%lld sectors) is greater than the size of the\n"
"device reported by the driver (%lld sectors).\n"
"However, a read of the device at the requested size\n"
"does succeed, so the requested size will be used.\n"),
fssize_db, max_fssize);
max_fssize = fssize_db;
}
if (max_fssize > ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX)
max_fssize = ((diskaddr_t)bsize/DEV_BSIZE) * INT_MAX;
range_check_64(&fssize_db, "size", 1024LL, max_fssize, max_fssize, 1);
if (fssize_db >= SECTORS_PER_TERABYTE) {
mtb = 'y';
if (!in_64bit_mode()) {
(void) fprintf(stderr, gettext(
"mkfs: Warning: Creating a file system greater than 1 terabyte on a\n"
" system running a 32-bit kernel. This file system will not be\n"
" accessible until the system is rebooted with a 64-bit kernel.\n"));
}
}
dbgprintf(("DeBuG mtb : %c\n", mtb));
if (mtb != 'y' && (ntrack == -1 || GROW_WITH_DEFAULT_TRAK ||
DEFAULT_SECT_TRAK_CPG)) {
if (label_type == LABEL_TYPE_EFI ||
label_type == LABEL_TYPE_OTHER) {
use_efi_dflts = 1;
retry = 1;
} else if (ioctl(fsi, DKIOCGGEOM, &dkg)) {
dbgprintf(("%s: Unable to read Disk geometry", fsys));
perror(gettext("Unable to read Disk geometry"));
lockexit(32);
} else {
nsect = dkg.dkg_nsect;
ntrack = dkg.dkg_nhead;
#ifdef i386
if (ntrack > 32 && (ntrack % 16) != 0) {
ntrack -= (ntrack % 16);
}
#endif
if (ioctl(fsi, DKIOCREMOVABLE, &isremovable)) {
dbgprintf(("DeBuG Unable to determine if %s is"
" Removable Media. Proceeding with system"
" determined parameters.\n", fsys));
isremovable = 0;
}
if (ioctl(fsi, DKIOCHOTPLUGGABLE, &ishotpluggable)) {
dbgprintf(("DeBuG Unable to determine if %s is"
" Hotpluggable Media. Proceeding with "
"system determined parameters.\n", fsys));
ishotpluggable = 0;
}
if ((((diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
dkg.dkg_nsect) > CHSLIMIT) || isremovable ||
ishotpluggable) {
use_efi_dflts = 1;
retry = 1;
}
}
}
dbgprintf(("DeBuG CHSLIMIT = %d geom = %llu\n", CHSLIMIT,
(diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead * dkg.dkg_nsect));
dbgprintf(("DeBuG label_type = %d isremovable = %d ishotpluggable = %d "
"use_efi_dflts = %d\n", label_type, isremovable, ishotpluggable,
use_efi_dflts));
if ((Nflag && use_efi_dflts) || (grow)) {
if (grow && ntrack_flag != RC_DEFAULT)
goto start_fs_creation;
rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize,
(char *)&altsblock);
ret = checksblock(altsblock, 1);
if (!ret) {
if (altsblock.fs_magic == MTB_UFS_MAGIC) {
mtb = 'y';
goto start_fs_creation;
}
use_efi_dflts = (altsblock.fs_version ==
UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
} else {
dbgprintf(("DeBuG checksblock() failed - error : %d"
" for sb : %d\n", ret, SBOFF/sectorsize));
rdfs((diskaddr_t)ALTSB, (int)sbsize,
(char *)&altsblock);
ret = checksblock(altsblock, 1);
if (!ret) {
if (altsblock.fs_magic == MTB_UFS_MAGIC) {
mtb = 'y';
goto start_fs_creation;
}
use_efi_dflts = (altsblock.fs_version ==
UFS_EFISTYLE4NONEFI_VERSION_2) ? 1 : 0;
}
dbgprintf(("DeBuG checksblock() returned : %d"
" for sb : %d\n", ret, ALTSB));
}
}
geom_nsect = nsect;
geom_ntrack = ntrack;
geom_cpg = cpg;
dbgprintf(("DeBuG geom_nsect=%d, geom_ntrack=%d, geom_cpg=%d\n",
geom_nsect, geom_ntrack, geom_cpg));
start_fs_creation:
retry_alternate_logic:
invalid_sb_cnt = 0;
cg_too_small = 0;
if (use_efi_dflts) {
nsect = DEF_SECTORS_EFI;
ntrack = DEF_TRACKS_EFI;
cpg = DESCPG;
dbgprintf(("\nDeBuG Using EFI defaults\n"));
} else {
nsect = geom_nsect;
ntrack = geom_ntrack;
cpg = geom_cpg;
dbgprintf(("\nDeBuG Using Geometry\n"));
range_check(&nsect, "nsect", 1, 32768, DFLNSECT, nsect_flag);
range_check(&ntrack, "ntrack", 1,
fssize_db > INT_MAX ? INT_MAX : (uint32_t)fssize_db,
DFLNTRAK, ntrack_flag);
}
range_check(&apc, "apc", 0, nsect - 1, 0, apc_flag);
if (mtb == 'y')
fragsize = bsize;
range_check(&fragsize, "fragsize", sectorsize, bsize,
MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize)), fragsize_flag);
if ((bsize / MAXFRAG) > fragsize) {
(void) fprintf(stderr, gettext(
"fragment size %ld is too small, minimum with block size %ld is %ld\n"),
fragsize, bsize, bsize / MAXFRAG);
(void) fprintf(stderr,
gettext("mkfs: fragsize reset to minimum %ld\n"),
bsize / MAXFRAG);
fragsize = bsize / MAXFRAG;
}
if (!POWEROF2(fragsize)) {
(void) fprintf(stderr,
gettext("fragment size must be a power of 2, not %ld\n"),
fragsize);
fragsize = MAX(bsize / MAXFRAG, MIN(DESFRAGSIZE, bsize));
(void) fprintf(stderr,
gettext("mkfs: fragsize reset to %ld\n"),
fragsize);
}
if (bsize < PAGESIZE) {
(void) fprintf(stderr, gettext(
"WARNING: filesystem block size (%ld) is smaller than "
"memory page size (%ld).\nResulting filesystem can not be "
"mounted on this system.\n\n"),
bsize, (long)PAGESIZE);
}
range_check(&rps, "rps", 1, 1000, DEFHZ, rps_flag);
range_check(&minfree, "free", 0, 99, MINFREE, minfree_flag);
range_check(&nrpos, "nrpos", 1, nsect, MIN(nsect, NRPOS), nrpos_flag);
if (mtb == 'y' && nbpi < MTB_NBPI) {
if (nbpi_flag != RC_DEFAULT)
(void) fprintf(stderr, gettext("mkfs: bad value for "
"nbpi: must be at least 1048576 for multi-terabyte,"
" nbpi reset to default 1048576\n"));
nbpi = MTB_NBPI;
}
if (mtb == 'y')
range_check(&nbpi, "nbpi", MTB_NBPI, 2 * MB, MTB_NBPI,
nbpi_flag);
else
range_check(&nbpi, "nbpi", DEV_BSIZE, 2 * MB, NBPI, nbpi_flag);
sblock.fs_bsize = bsize;
sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode);
if (mtb == 'n') {
maxcpg = (bsize - sizeof (struct cg) -
howmany(MAXIpG(&sblock), NBBY)) /
(sizeof (long) + nrpos * sizeof (short) +
nsect / (MAXFRAG * NBBY));
} else {
maxcpg = compute_maxcpg(bsize, fragsize, nbpi, nrpos,
nsect * ntrack);
}
dbgprintf(("DeBuG cpg : %ld\n", cpg));
if (cpg == -1 || (mtb == 'y' && cpg_flag == RC_DEFAULT))
cpg = maxcpg;
dbgprintf(("DeBuG cpg : %ld\n", cpg));
range_check(&cpg, "cgsize", 1, maxcpg, MIN(maxcpg, DESCPG), cpg_flag);
islog = 0;
islogok = 0;
waslog = 0;
if (Pflag) {
(void) printf("%llu\n", probe_summaryinfo());
exit(0);
}
if (grow) {
sigact.sa_handler = recover_from_sigint;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = SA_RESTART;
if (sigaction(SIGINT, &sigact, (struct sigaction *)NULL) < 0) {
perror(gettext("Could not register SIGINT handler"));
lockexit(3);
}
}
if (!Nflag) {
if (statvfs64(MNTTAB, &fs) < 0) {
(void) fprintf(stderr, gettext("can't statvfs %s\n"),
MNTTAB);
exit(32);
}
if (strcmp(MNTTYPE_MNTFS, fs.f_basetype) != 0) {
(void) fprintf(stderr, gettext(
"%s file system type is not %s, can't mkfs\n"),
MNTTAB, MNTTYPE_MNTFS);
exit(32);
}
special = getfullblkname(fsys);
checkdev(fsys, special);
if ((special != NULL) && (*special != '\0')) {
if ((mnttab = fopen(MNTTAB, "r")) == NULL) {
(void) fprintf(stderr, gettext(
"can't open %s\n"), MNTTAB);
exit(32);
}
while ((getmntent(mnttab, &mntp)) == 0) {
if (grow) {
checkmount(&mntp, special);
continue;
}
if (strcmp(special, mntp.mnt_special) == 0) {
(void) fprintf(stderr, gettext(
"%s is mounted, can't mkfs\n"),
special);
exit(32);
}
}
(void) fclose(mnttab);
}
if (directory && (ismounted == 0)) {
(void) fprintf(stderr, gettext("%s is not mounted\n"),
special);
lockexit(32);
}
fso = (grow) ? open64(fsys, O_WRONLY) : creat64(fsys, 0666);
if (fso < 0) {
saverr = errno;
(void) fprintf(stderr,
gettext("%s: cannot create: %s\n"),
fsys, strerror(saverr));
lockexit(32);
}
} else {
fso = open64(fsys, O_RDONLY);
if (fso < 0) {
saverr = errno;
(void) fprintf(stderr, gettext("%s: cannot open: %s\n"),
fsys, strerror(saverr));
lockexit(32);
}
}
if (ioctl(fso, DKIOCGMEDIAINFO, &dkminfo) != -1) {
if (dkminfo.dki_lbsize != 0 &&
POWEROF2(dkminfo.dki_lbsize / DEV_BSIZE) &&
dkminfo.dki_lbsize != DEV_BSIZE) {
fprintf(stderr,
gettext("The device sector size %u is not "
"supported by ufs!\n"), dkminfo.dki_lbsize);
(void) close(fso);
exit(1);
}
}
#ifdef MKFS_DEBUG
srand48(12962);
#else
srand48((long)(time((time_t *)NULL) + getpid()));
#endif
if (grow) {
growinit(fsys);
goto grow00;
}
rdfs(fssize_db - 1, (int)sectorsize, (char *)&sblock);
rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
sblock.fs_magic = -1;
sblock.fs_clean = FSBAD;
sblock.fs_state = FSOKAY - sblock.fs_time;
wtfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
bzero(&sblock, (size_t)sbsize);
sblock.fs_nsect = nsect;
sblock.fs_ntrak = ntrack;
sblock.fs_spc = sblock.fs_ntrak * sblock.fs_nsect;
grow00:
if (apc_flag) {
sblock.fs_spc -= apc;
}
if (sblock.fs_spc != sblock.fs_ntrak * sblock.fs_nsect) {
spc_flag = 1;
}
if (grow)
goto grow10;
sblock.fs_nrpos = nrpos;
sblock.fs_bsize = bsize;
sblock.fs_fsize = fragsize;
sblock.fs_minfree = minfree;
grow10:
if (nbpi < sblock.fs_fsize) {
(void) fprintf(stderr, gettext(
"warning: wasteful data byte allocation / inode (nbpi):\n"));
(void) fprintf(stderr, gettext(
"%ld smaller than allocatable fragment size of %d\n"),
nbpi, sblock.fs_fsize);
}
if (grow)
goto grow20;
if (opt == 's')
sblock.fs_optim = FS_OPTSPACE;
else
sblock.fs_optim = FS_OPTTIME;
sblock.fs_bmask = ~(sblock.fs_bsize - 1);
sblock.fs_fmask = ~(sblock.fs_fsize - 1);
#if defined(_BIG_ENDIAN)
sblock.fs_qbmask.val[0] = 0;
sblock.fs_qbmask.val[1] = ~sblock.fs_bmask;
sblock.fs_qfmask.val[0] = 0;
sblock.fs_qfmask.val[1] = ~sblock.fs_fmask;
#endif
#if defined(_LITTLE_ENDIAN)
sblock.fs_qbmask.val[0] = ~sblock.fs_bmask;
sblock.fs_qbmask.val[1] = 0;
sblock.fs_qfmask.val[0] = ~sblock.fs_fmask;
sblock.fs_qfmask.val[1] = 0;
#endif
for (sblock.fs_bshift = 0, i = sblock.fs_bsize; i > 1; i >>= 1)
sblock.fs_bshift++;
for (sblock.fs_fshift = 0, i = sblock.fs_fsize; i > 1; i >>= 1)
sblock.fs_fshift++;
sblock.fs_frag = numfrags(&sblock, sblock.fs_bsize);
for (sblock.fs_fragshift = 0, i = sblock.fs_frag; i > 1; i >>= 1)
sblock.fs_fragshift++;
if (sblock.fs_frag > MAXFRAG) {
(void) fprintf(stderr, gettext(
"fragment size %d is too small, minimum with block size %d is %d\n"),
sblock.fs_fsize, sblock.fs_bsize,
sblock.fs_bsize / MAXFRAG);
lockexit(32);
}
sblock.fs_nindir = sblock.fs_bsize / sizeof (daddr32_t);
sblock.fs_inopb = sblock.fs_bsize / sizeof (struct dinode);
sblock.fs_nspf = sblock.fs_fsize / sectorsize;
for (sblock.fs_fsbtodb = 0, i = NSPF(&sblock); i > 1; i >>= 1)
sblock.fs_fsbtodb++;
sblock.fs_sblkno =
roundup(howmany(bbsize + sbsize, sblock.fs_fsize), sblock.fs_frag);
sblock.fs_cblkno = (daddr32_t)(sblock.fs_sblkno +
roundup(howmany(sbsize, sblock.fs_fsize), sblock.fs_frag));
sblock.fs_iblkno = sblock.fs_cblkno + sblock.fs_frag;
sblock.fs_cgoffset = roundup(
howmany(sblock.fs_nsect, NSPF(&sblock)), sblock.fs_frag);
for (sblock.fs_cgmask = -1, i = sblock.fs_ntrak; i > 1; i >>= 1)
sblock.fs_cgmask <<= 1;
if (!POWEROF2(sblock.fs_ntrak))
sblock.fs_cgmask <<= 1;
for (sblock.fs_cpc = NSPB(&sblock), i = sblock.fs_spc;
sblock.fs_cpc > 1 && (i & 1) == 0;
sblock.fs_cpc >>= 1, i >>= 1)
;
mincpc = sblock.fs_cpc;
bpcg = (uint64_t)sblock.fs_spc * sectorsize;
inospercg = (uint64_t)roundup(bpcg / sizeof (struct dinode),
INOPB(&sblock));
if (inospercg > MAXIpG(&sblock))
inospercg = MAXIpG(&sblock);
used = (uint64_t)(sblock.fs_iblkno + inospercg /
INOPF(&sblock)) * NSPF(&sblock);
mincpgcnt = (long)howmany((uint64_t)sblock.fs_cgoffset *
(~sblock.fs_cgmask) + used, sblock.fs_spc);
mincpg = roundup(mincpgcnt, mincpc);
sblock.fs_cpg = mincpg;
sblock.fs_ipg = (int32_t)inospercg;
mapcramped = 0;
while (CGSIZE(&sblock) > sblock.fs_bsize) {
mapcramped = 1;
if (sblock.fs_bsize < MAXBSIZE) {
sblock.fs_bsize <<= 1;
if ((i & 1) == 0) {
i >>= 1;
} else {
sblock.fs_cpc <<= 1;
mincpc <<= 1;
mincpg = roundup(mincpgcnt, mincpc);
sblock.fs_cpg = mincpg;
}
sblock.fs_frag <<= 1;
sblock.fs_fragshift += 1;
if (sblock.fs_frag <= MAXFRAG)
continue;
}
if (sblock.fs_fsize == sblock.fs_bsize) {
(void) fprintf(stderr, gettext(
"There is no block size that can support this disk\n"));
lockexit(32);
}
sblock.fs_frag >>= 1;
sblock.fs_fragshift -= 1;
sblock.fs_fsize <<= 1;
sblock.fs_nspf <<= 1;
}
inodecramped = 0;
used *= sectorsize;
nbytes64 = (uint64_t)mincpg * bpcg - used;
inospercg = (uint64_t)roundup((nbytes64 / nbpi), INOPB(&sblock));
sblock.fs_ipg = (int32_t)inospercg;
while (inospercg > MAXIpG(&sblock)) {
inodecramped = 1;
if (mincpc == 1 || sblock.fs_frag == 1 ||
sblock.fs_bsize == MINBSIZE)
break;
nbytes64 = (uint64_t)mincpg * bpcg - used;
(void) fprintf(stderr,
gettext("With a block size of %d %s %lu\n"),
sblock.fs_bsize, gettext("minimum bytes per inode is"),
(uint32_t)(nbytes64 / MAXIpG(&sblock) + 1));
sblock.fs_bsize >>= 1;
sblock.fs_frag >>= 1;
sblock.fs_fragshift -= 1;
mincpc >>= 1;
sblock.fs_cpg = roundup(mincpgcnt, mincpc);
if (CGSIZE(&sblock) > sblock.fs_bsize) {
sblock.fs_bsize <<= 1;
break;
}
mincpg = sblock.fs_cpg;
nbytes64 = (uint64_t)mincpg * bpcg - used;
inospercg = (uint64_t)roundup((nbytes64 / nbpi),
INOPB(&sblock));
sblock.fs_ipg = (int32_t)inospercg;
}
if (inodecramped) {
if (inospercg > MAXIpG(&sblock)) {
nbytes64 = (uint64_t)mincpg * bpcg - used;
(void) fprintf(stderr, gettext(
"Minimum bytes per inode is %d\n"),
(uint32_t)(nbytes64 / MAXIpG(&sblock) + 1));
} else if (!mapcramped) {
(void) fprintf(stderr, gettext(
"With %ld bytes per inode, minimum cylinders per group is %ld\n"),
nbpi, mincpg);
}
}
if (mapcramped) {
(void) fprintf(stderr, gettext(
"With %d sectors per cylinder, minimum cylinders "
"per group is %ld\n"),
sblock.fs_spc, mincpg);
}
if (inodecramped || mapcramped) {
if ((sblock.fs_bsize != bsize) &&
(sblock.fs_fsize != fragsize)) {
(void) fprintf(stderr, gettext(
"This requires the block size to be changed from %ld to %d\n"
"and the fragment size to be changed from %ld to %d\n"),
bsize, sblock.fs_bsize,
fragsize, sblock.fs_fsize);
} else if (sblock.fs_bsize != bsize) {
(void) fprintf(stderr, gettext(
"This requires the block size to be changed from %ld to %d\n"),
bsize, sblock.fs_bsize);
} else if (sblock.fs_fsize != fragsize) {
(void) fprintf(stderr, gettext(
"This requires the fragment size to be changed from %ld to %d\n"),
fragsize, sblock.fs_fsize);
} else {
(void) fprintf(stderr, gettext(
"Unable to make filesystem fit with the given constraints\n"));
}
(void) fprintf(stderr, gettext(
"Please re-run mkfs with corrected parameters\n"));
lockexit(32);
}
sblock.fs_cpg = cpg;
if (sblock.fs_cpg % mincpc != 0) {
(void) fprintf(stderr, gettext(
"Warning: cylinder groups must have a multiple "
"of %ld cylinders with the given\n parameters\n"),
mincpc);
sblock.fs_cpg = roundup(sblock.fs_cpg, mincpc);
(void) fprintf(stderr, gettext("Rounded cgsize up to %d\n"),
sblock.fs_cpg);
}
nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi), INOPB(&sblock));
while (sblock.fs_ipg > MAXIpG(&sblock)) {
inodecramped = 1;
sblock.fs_cpg -= mincpc;
nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi),
INOPB(&sblock));
}
while (CGSIZE(&sblock) > sblock.fs_bsize) {
mapcramped = 1;
sblock.fs_cpg -= mincpc;
nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
sblock.fs_ipg = roundup((uint32_t)(nbytes64 / nbpi),
INOPB(&sblock));
}
sblock.fs_fpg = (sblock.fs_cpg * sblock.fs_spc) / NSPF(&sblock);
if ((sblock.fs_cpg * sblock.fs_spc) % NSPB(&sblock) != 0) {
(void) fprintf(stderr,
gettext("newfs: panic (fs_cpg * fs_spc) %% NSPF != 0\n"));
lockexit(32);
}
if (sblock.fs_cpg < mincpg) {
(void) fprintf(stderr, gettext(
"With the given parameters, cgsize must be at least %ld; please re-run mkfs\n"),
mincpg);
lockexit(32);
}
sblock.fs_cgsize = fragroundup(&sblock, CGSIZE(&sblock));
grow20:
fssize_frag = (int64_t)dbtofsb(&sblock, fssize_db);
if (fssize_frag > INT_MAX) {
(void) fprintf(stderr, gettext(
"There are too many fragments in the system, increase fragment size\n"),
mincpg);
lockexit(32);
}
sblock.fs_size = (int32_t)fssize_frag;
sblock.fs_ncyl = (int32_t)(fssize_frag * NSPF(&sblock) / sblock.fs_spc);
if (fssize_frag * NSPF(&sblock) >
(uint64_t)sblock.fs_ncyl * sblock.fs_spc) {
sblock.fs_ncyl++;
warn = 1;
}
if (sblock.fs_ncyl < 1) {
(void) fprintf(stderr, gettext(
"file systems must have at least one cylinder\n"));
lockexit(32);
}
if (grow)
goto grow30;
sblock.fs_postblformat = FS_DYNAMICPOSTBLFMT;
sblock.fs_sbsize = fragroundup(&sblock, sizeof (struct fs));
sblock.fs_npsect = sblock.fs_nsect;
if (sblock.fs_ntrak == 1) {
sblock.fs_cpc = 0;
goto next;
}
postblsize = sblock.fs_nrpos * sblock.fs_cpc * sizeof (short);
rotblsize = sblock.fs_cpc * sblock.fs_spc / NSPB(&sblock);
totalsbsize = sizeof (struct fs) + rotblsize;
if (sblock.fs_nrpos == 8 && sblock.fs_cpc <= 16) {
sblock.fs_postbloff = (char *)(&sblock.fs_opostbl[0][0]) -
(char *)(&sblock.fs_link);
sblock.fs_rotbloff = &sblock.fs_space[0] -
(uchar_t *)(&sblock.fs_link);
} else {
sblock.fs_postbloff = &sblock.fs_space[0] -
(uchar_t *)(&sblock.fs_link);
sblock.fs_rotbloff = sblock.fs_postbloff + postblsize;
totalsbsize += postblsize;
}
if (totalsbsize > sblock.fs_bsize ||
sblock.fs_nsect > (1 << NBBY) * NSPB(&sblock)) {
(void) fprintf(stderr, gettext(
"Warning: insufficient space in super block for\n"
"rotational layout tables with nsect %d, ntrack %d, "
"and nrpos %d.\nOmitting tables - file system "
"performance may be impaired.\n"),
sblock.fs_nsect, sblock.fs_ntrak, sblock.fs_nrpos);
sblock.fs_cpc = 0;
goto next;
}
sblock.fs_sbsize = fragroundup(&sblock, totalsbsize);
for (cylno = 0; cylno < sblock.fs_cpc; cylno++)
for (rpos = 0; rpos < sblock.fs_nrpos; rpos++)
fs_postbl(&sblock, cylno)[rpos] = -1;
for (i = (rotblsize - 1) * sblock.fs_frag;
i >= 0; i -= sblock.fs_frag) {
cylno = cbtocylno(&sblock, i);
rpos = cbtorpos(&sblock, i);
blk = fragstoblks(&sblock, i);
if (fs_postbl(&sblock, cylno)[rpos] == -1)
fs_rotbl(&sblock)[blk] = 0;
else
fs_rotbl(&sblock)[blk] =
fs_postbl(&sblock, cylno)[rpos] - blk;
fs_postbl(&sblock, cylno)[rpos] = blk;
}
next:
grow30:
sblock.fs_ncg = sblock.fs_ncyl / sblock.fs_cpg;
if (sblock.fs_ncyl % sblock.fs_cpg)
sblock.fs_ncg++;
sblock.fs_dblkno = sblock.fs_iblkno + sblock.fs_ipg / INOPF(&sblock);
i = MIN(~sblock.fs_cgmask, sblock.fs_ncg - 1);
ibpcl = cgdmin(&sblock, i) - cgbase(&sblock, i);
if (ibpcl >= sblock.fs_fpg) {
(void) fprintf(stderr, gettext(
"inode blocks/cyl group (%d) >= data blocks (%d)\n"),
cgdmin(&sblock, i) - cgbase(&sblock, i) / sblock.fs_frag,
sblock.fs_fpg / sblock.fs_frag);
if ((ibpcl < 0) || (sblock.fs_fpg < 0)) {
(void) fprintf(stderr, gettext(
"number of cylinders per cylinder group (%d) must be decreased.\n"),
sblock.fs_cpg);
} else {
(void) fprintf(stderr, gettext(
"number of cylinders per cylinder group (%d) must be increased.\n"),
sblock.fs_cpg);
}
(void) fprintf(stderr, gettext(
"Note that cgsize may have been adjusted to allow struct cg to fit.\n"));
lockexit(32);
}
j = sblock.fs_ncg - 1;
if ((i = fssize_frag - j * sblock.fs_fpg) < sblock.fs_fpg &&
cgdmin(&sblock, j) - cgbase(&sblock, j) > i) {
(void) fprintf(stderr, gettext(
"Warning: inode blocks/cyl group (%d) >= data "
"blocks (%ld) in last\n cylinder group. This "
"implies %ld sector(s) cannot be allocated.\n"),
(cgdmin(&sblock, j) - cgbase(&sblock, j)) / sblock.fs_frag,
i / sblock.fs_frag, i * NSPF(&sblock));
if (sblock.fs_ncg == 1)
cg_too_small = 1;
sblock.fs_ncg--;
sblock.fs_ncyl = sblock.fs_ncg * sblock.fs_cpg;
sblock.fs_size = fssize_frag =
(int64_t)sblock.fs_ncyl * (int64_t)sblock.fs_spc /
(int64_t)NSPF(&sblock);
warn = 0;
}
if (warn && !spc_flag) {
(void) fprintf(stderr, gettext(
"Warning: %d sector(s) in last cylinder unallocated\n"),
sblock.fs_spc - (uint32_t)(fssize_frag * NSPF(&sblock) -
(uint64_t)(sblock.fs_ncyl - 1) * sblock.fs_spc));
}
sblock.fs_csaddr = cgdmin(&sblock, 0);
sblock.fs_cssize =
fragroundup(&sblock, sblock.fs_ncg * sizeof (struct csum));
i = sblock.fs_bsize / sizeof (struct csum);
sblock.fs_csmask = ~(i - 1);
for (sblock.fs_csshift = 0; i > 1; i >>= 1)
sblock.fs_csshift++;
fscs = (struct csum *)calloc(1, sblock.fs_cssize);
checksummarysize();
if (mtb == 'y') {
sblock.fs_magic = MTB_UFS_MAGIC;
sblock.fs_version = MTB_UFS_VERSION_1;
} else {
sblock.fs_magic = FS_MAGIC;
if (use_efi_dflts)
sblock.fs_version = UFS_EFISTYLE4NONEFI_VERSION_2;
else
sblock.fs_version = UFS_VERSION_MIN;
}
if (grow) {
bcopy((caddr_t)grow_fscs, (caddr_t)fscs, (int)grow_fs_cssize);
extendsummaryinfo();
goto grow40;
}
sblock.fs_rotdelay = rotdelay;
sblock.fs_maxcontig = maxcontig;
sblock.fs_maxbpg = MAXBLKPG(sblock.fs_bsize);
sblock.fs_rps = rps;
sblock.fs_cgrotor = 0;
sblock.fs_cstotal.cs_ndir = 0;
sblock.fs_cstotal.cs_nbfree = 0;
sblock.fs_cstotal.cs_nifree = 0;
sblock.fs_cstotal.cs_nffree = 0;
sblock.fs_fmod = 0;
sblock.fs_ronly = 0;
sblock.fs_time = mkfstime;
sblock.fs_state = FSOKAY - sblock.fs_time;
sblock.fs_clean = FSCLEAN;
grow40:
if (rflag) {
dump_sblock();
lockexit(0);
}
(void) fprintf(stderr, gettext(
"%s:\t%lld sectors in %d cylinders of %d tracks, %d sectors\n"),
fsys, (uint64_t)sblock.fs_size * NSPF(&sblock), sblock.fs_ncyl,
sblock.fs_ntrak, sblock.fs_nsect);
(void) fprintf(stderr, gettext(
"\t%.1fMB in %d cyl groups (%d c/g, %.2fMB/g, %d i/g)\n"),
(float)sblock.fs_size * sblock.fs_fsize / MB, sblock.fs_ncg,
sblock.fs_cpg, (float)sblock.fs_fpg * sblock.fs_fsize / MB,
sblock.fs_ipg);
tmpbuf = calloc(sblock.fs_ncg / 50 + 500, 1);
if (tmpbuf == NULL) {
perror("calloc");
lockexit(32);
}
if (cg_too_small) {
(void) fprintf(stderr, gettext("File system creation failed. "
"There is only one cylinder group and\nthat is "
"not even big enough to hold the inodes.\n"));
lockexit(32);
}
tprintf(gettext(
"super-block backups (for fsck -F ufs -o b=#) at:\n"));
for (width = cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++) {
if ((grow == 0) || (cylno >= grow_fs_ncg))
initcg(cylno);
num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno));
if (Nflag && retry) {
skip_this_sb = 0;
rdfs((diskaddr_t)num, sbsize, (char *)&altsblock);
ret = checksblock(altsblock, 1);
if (ret) {
skip_this_sb = 1;
invalid_sb_cnt++;
dbgprintf(("DeBuG checksblock() failed - error"
" : %d for sb : %llu invalid_sb_cnt : %d\n",
ret, num, invalid_sb_cnt));
} else {
if (use_efi_dflts && altsblock.fs_version
!= UFS_EFISTYLE4NONEFI_VERSION_2) {
skip_this_sb = 1;
invalid_sb_cnt++;
}
}
if (invalid_sb_cnt >= INVALIDSBLIMIT) {
if (retry > 1) {
(void) fprintf(stderr, gettext(
"Error determining alternate "
"superblock locations\n"));
free(tmpbuf);
lockexit(32);
}
retry++;
use_efi_dflts = !use_efi_dflts;
free(tmpbuf);
goto retry_alternate_logic;
}
if (skip_this_sb)
continue;
}
(void) sprintf(pbuf, " %llu,", num);
plen = strlen(pbuf);
if ((width + plen) > (WIDTH - 1)) {
width = plen;
tprintf("\n");
} else {
width += plen;
}
if (Nflag && retry)
(void) strncat(tmpbuf, pbuf, strlen(pbuf));
else
(void) fprintf(stderr, "%s", pbuf);
}
tprintf("\n");
remaining_cg = sblock.fs_ncg - cylno;
if (remaining_cg > 300) {
tprintf(gettext("Initializing cylinder groups:\n"));
do_dot = 1;
}
i = 0;
for (; cylno < sblock.fs_ncg - 10; cylno++) {
if ((grow == 0) || (cylno >= grow_fs_ncg))
initcg(cylno);
if (do_dot && cylno % 50 == 0) {
tprintf(".");
i++;
if (i == WIDTH - 1) {
tprintf("\n");
i = 0;
}
}
}
if (do_dot) {
tprintf(gettext(
"\nsuper-block backups for last 10 cylinder groups at:\n"));
}
for (width = 0; cylno < sblock.fs_ncg; cylno++) {
if ((grow == 0) || (cylno >= grow_fs_ncg))
initcg(cylno);
num = fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno));
if (Nflag && retry) {
skip_this_sb = 0;
rdfs((diskaddr_t)num, sbsize, (char *)&altsblock);
ret = checksblock(altsblock, 1);
if (ret) {
skip_this_sb = 1;
invalid_sb_cnt++;
dbgprintf(("DeBuG checksblock() failed - error"
" : %d for sb : %llu invalid_sb_cnt : %d\n",
ret, num, invalid_sb_cnt));
} else {
if (use_efi_dflts && altsblock.fs_version
!= UFS_EFISTYLE4NONEFI_VERSION_2) {
skip_this_sb = 1;
invalid_sb_cnt++;
}
}
if (invalid_sb_cnt >= INVALIDSBLIMIT) {
if (retry > 1) {
(void) fprintf(stderr, gettext(
"Error determining alternate "
"superblock locations\n"));
free(tmpbuf);
lockexit(32);
}
retry++;
use_efi_dflts = !use_efi_dflts;
free(tmpbuf);
goto retry_alternate_logic;
}
if (skip_this_sb)
continue;
}
if (cylno == sblock.fs_ncg-1)
(void) sprintf(pbuf, " %llu", num);
else
(void) sprintf(pbuf, " %llu,", num);
plen = strlen(pbuf);
if ((width + plen) > (WIDTH - 1)) {
width = plen;
tprintf("\n");
} else {
width += plen;
}
if (Nflag && retry)
(void) strncat(tmpbuf, pbuf, strlen(pbuf));
else
(void) fprintf(stderr, "%s", pbuf);
}
tprintf("\n");
if (Nflag) {
if (retry)
(void) fprintf(stderr, "%s", tmpbuf);
free(tmpbuf);
lockexit(0);
}
free(tmpbuf);
if (grow)
goto grow50;
fsinit();
grow50:
wtsb();
if (grow) {
extendcg(grow_fs_ncg-1);
wtsb();
}
for (cylno = 0; cylno < sblock.fs_ncg && cylno < 10; cylno++)
awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)),
(int)sbsize, (char *)&sblock, SAVE);
if (mtb == 'y') {
if (sblock.fs_ncg <= 10)
cylno = sblock.fs_ncg;
else if (sblock.fs_ncg <= 20)
cylno = 10;
else
cylno = sblock.fs_ncg - 10;
}
for (; cylno < sblock.fs_ncg; cylno++)
awtfs(fsbtodb(&sblock, (uint64_t)cgsblock(&sblock, cylno)),
(int)sbsize, (char *)&sblock, SAVE);
flush_writes();
if (grow)
sblock.fs_clean = grow_fs_clean;
else
sblock.fs_clean = FSCLEAN;
sblock.fs_time = mkfstime;
sblock.fs_state = FSOKAY - sblock.fs_time;
wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
isbad = 0;
if (fsync(fso) == -1) {
saverr = errno;
(void) fprintf(stderr,
gettext("mkfs: fsync failed on write disk: %s\n"),
strerror(saverr));
}
if (close(fsi) == -1) {
saverr = errno;
(void) fprintf(stderr,
gettext("mkfs: close failed on read disk: %s\n"),
strerror(saverr));
}
if (close(fso) == -1) {
saverr = errno;
(void) fprintf(stderr,
gettext("mkfs: close failed on write disk: %s\n"),
strerror(saverr));
}
fsi = fso = -1;
#ifndef STANDALONE
lockexit(0);
#endif
return (0);
}
static diskaddr_t
get_device_size(int fd)
{
struct dk_minfo disk_info;
if ((ioctl(fd, DKIOCGMEDIAINFO, (caddr_t)&disk_info)) == -1)
return (0);
return (disk_info.dki_capacity);
}
static diskaddr_t
get_max_size(int fd)
{
struct extvtoc vtoc;
dk_gpt_t *efi_vtoc;
diskaddr_t slicesize;
int index = read_extvtoc(fd, &vtoc);
if (index >= 0) {
label_type = LABEL_TYPE_VTOC;
} else {
if (index == VT_ENOTSUP || index == VT_ERROR) {
index = efi_alloc_and_read(fd, &efi_vtoc);
label_type = LABEL_TYPE_EFI;
}
}
if (index < 0) {
label_type = LABEL_TYPE_OTHER;
slicesize = get_device_size(fd);
if (slicesize == 0) {
switch (index) {
case VT_ERROR:
break;
case VT_EIO:
errno = EIO;
break;
case VT_EINVAL:
errno = EINVAL;
}
perror(gettext("Can not determine partition size"));
lockexit(32);
}
}
if (label_type == LABEL_TYPE_EFI) {
slicesize = efi_vtoc->efi_parts[index].p_size;
efi_free(efi_vtoc);
} else if (label_type == LABEL_TYPE_VTOC) {
slicesize = (uint32_t)vtoc.v_part[index].p_size;
}
dbgprintf(("DeBuG get_max_size index = %d, p_size = %lld, "
"dolimit = %d\n", index, slicesize, (slicesize > FS_MAX)));
if (slicesize > FS_MAX)
return (FS_MAX);
return (slicesize);
}
static long
get_max_track_size(int fd)
{
struct dk_cinfo ci;
long track_size = -1;
if (ioctl(fd, DKIOCINFO, &ci) == 0) {
track_size = ci.dki_maxtransfer * DEV_BSIZE;
}
if ((track_size < 0)) {
int error = 0;
int maxphys;
int gotit = 0;
gotit = fsgetmaxphys(&maxphys, &error);
if (gotit) {
track_size = MIN(MB, maxphys);
} else {
(void) fprintf(stderr, gettext(
"Warning: Could not get system value for maxphys. The value for\n"
"maxcontig will default to 1MB.\n"));
track_size = MB;
}
}
return (track_size);
}
static void
initcg(int cylno)
{
diskaddr_t cbase, d;
diskaddr_t dlower;
diskaddr_t dupper;
diskaddr_t dmax;
int64_t i;
struct csum *cs;
struct dinode *inode_buffer;
int size;
diskaddr_t bno;
int cbcylno;
int cbcylno_sect;
int cbsect_incr;
short *cgblks;
int trackrpos;
int trackoff;
int trackoff_incr;
int rpos;
int rpos_incr;
union cgun *icgun;
#define icg (icgun->cg)
icgun = (union cgun *)getbuf(&cgsumbuf, sizeof (union cgun));
cbase = cgbase(&sblock, cylno);
dmax = cbase + sblock.fs_fpg;
if (dmax > sblock.fs_size)
dmax = sblock.fs_size;
dlower = cgsblock(&sblock, cylno) - cbase;
dupper = cgdmin(&sblock, cylno) - cbase;
if (cylno == 0)
dupper += howmany(sblock.fs_cssize, sblock.fs_fsize);
cs = fscs + cylno;
icg.cg_time = mkfstime;
icg.cg_magic = CG_MAGIC;
icg.cg_cgx = cylno;
if (cylno == sblock.fs_ncg - 1)
icg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno);
else
icg.cg_ncyl = sblock.fs_cpg;
icg.cg_niblk = sblock.fs_ipg;
icg.cg_ndblk = dmax - cbase;
icg.cg_cs.cs_ndir = 0;
icg.cg_cs.cs_nffree = 0;
icg.cg_cs.cs_nbfree = 0;
icg.cg_cs.cs_nifree = 0;
icg.cg_rotor = 0;
icg.cg_frotor = 0;
icg.cg_irotor = 0;
icg.cg_btotoff = &icg.cg_space[0] - (uchar_t *)(&icg.cg_link);
icg.cg_boff = icg.cg_btotoff + sblock.fs_cpg * sizeof (long);
icg.cg_iusedoff = icg.cg_boff +
sblock.fs_cpg * sblock.fs_nrpos * sizeof (short);
icg.cg_freeoff = icg.cg_iusedoff + howmany(sblock.fs_ipg, NBBY);
icg.cg_nextfreeoff = icg.cg_freeoff +
howmany(sblock.fs_cpg * sblock.fs_spc / NSPF(&sblock), NBBY);
for (i = 0; i < sblock.fs_frag; i++) {
icg.cg_frsum[i] = 0;
}
bzero((caddr_t)cg_inosused(&icg), icg.cg_freeoff - icg.cg_iusedoff);
icg.cg_cs.cs_nifree += sblock.fs_ipg;
if (cylno == 0)
for (i = 0; i < UFSROOTINO; i++) {
setbit(cg_inosused(&icg), i);
icg.cg_cs.cs_nifree--;
}
size = sblock.fs_ipg * sizeof (struct dinode);
inode_buffer = (struct dinode *)getbuf(&inodebuf, size);
for (i = 0; i < sblock.fs_ipg; i++) {
IRANDOMIZE(&(inode_buffer[i].di_ic));
}
awtfs(fsbtodb(&sblock, (uint64_t)cgimin(&sblock, cylno)), (int)size,
(char *)inode_buffer, RELEASE);
bzero((caddr_t)cg_blktot(&icg), icg.cg_boff - icg.cg_btotoff);
bzero((caddr_t)cg_blks(&sblock, &icg, 0),
icg.cg_iusedoff - icg.cg_boff);
bzero((caddr_t)cg_blksfree(&icg), icg.cg_nextfreeoff - icg.cg_freeoff);
if (cylno > 0) {
for (d = 0; d < dlower; d += sblock.fs_frag) {
setblock(&sblock, cg_blksfree(&icg), d/sblock.fs_frag);
icg.cg_cs.cs_nbfree++;
cg_blktot(&icg)[cbtocylno(&sblock, d)]++;
cg_blks(&sblock, &icg, cbtocylno(&sblock, d))
[cbtorpos(&sblock, d)]++;
}
sblock.fs_dsize += dlower;
}
sblock.fs_dsize += icg.cg_ndblk - dupper;
if ((i = dupper % sblock.fs_frag) != 0) {
icg.cg_frsum[sblock.fs_frag - i]++;
for (d = dupper + sblock.fs_frag - i; dupper < d; dupper++) {
setbit(cg_blksfree(&icg), dupper);
icg.cg_cs.cs_nffree++;
}
}
cbcylno_sect = dupper * NSPF(&sblock);
cbsect_incr = sblock.fs_frag * NSPF(&sblock);
cbcylno = cbcylno_sect / sblock.fs_spc;
cbcylno_sect %= sblock.fs_spc;
cgblks = cg_blks(&sblock, &icg, cbcylno);
bno = dupper / sblock.fs_frag;
if (!spc_flag) {
trackrpos = (cbcylno_sect % sblock.fs_nsect) * sblock.fs_nrpos;
rpos = trackrpos / sblock.fs_nsect;
trackoff = trackrpos % sblock.fs_nsect;
trackoff_incr = cbsect_incr * sblock.fs_nrpos;
rpos_incr = (trackoff_incr / sblock.fs_nsect) % sblock.fs_nrpos;
trackoff_incr = trackoff_incr % sblock.fs_nsect;
}
for (d = dupper; d + sblock.fs_frag <= dmax - cbase; ) {
setblock(&sblock, cg_blksfree(&icg), bno);
icg.cg_cs.cs_nbfree++;
cg_blktot(&icg)[cbcylno]++;
if (!spc_flag)
cgblks[rpos]++;
else
cg_blks(&sblock, &icg, cbtocylno(&sblock, d))
[cbtorpos(&sblock, d)]++;
d += sblock.fs_frag;
bno++;
cbcylno_sect += cbsect_incr;
if (cbcylno_sect >= sblock.fs_spc) {
cbcylno++;
cbcylno_sect -= sblock.fs_spc;
cgblks += sblock.fs_nrpos;
}
if (!spc_flag) {
trackoff += trackoff_incr;
rpos += rpos_incr;
if (trackoff >= sblock.fs_nsect) {
trackoff -= sblock.fs_nsect;
rpos++;
}
if (rpos >= sblock.fs_nrpos)
rpos -= sblock.fs_nrpos;
}
}
if (d < dmax - cbase) {
icg.cg_frsum[dmax - cbase - d]++;
for (; d < dmax - cbase; d++) {
setbit(cg_blksfree(&icg), d);
icg.cg_cs.cs_nffree++;
}
}
sblock.fs_cstotal.cs_ndir += icg.cg_cs.cs_ndir;
sblock.fs_cstotal.cs_nffree += icg.cg_cs.cs_nffree;
sblock.fs_cstotal.cs_nbfree += icg.cg_cs.cs_nbfree;
sblock.fs_cstotal.cs_nifree += icg.cg_cs.cs_nifree;
*cs = icg.cg_cs;
awtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, cylno)),
sblock.fs_bsize, (char *)&icg, RELEASE);
}
struct inode node;
#define LOSTDIR
#ifdef LOSTDIR
#define PREDEFDIR 3
#else
#define PREDEFDIR 2
#endif
struct direct root_dir[] = {
{ UFSROOTINO, sizeof (struct direct), 1, "." },
{ UFSROOTINO, sizeof (struct direct), 2, ".." },
#ifdef LOSTDIR
{ LOSTFOUNDINO, sizeof (struct direct), 10, "lost+found" },
#endif
};
#ifdef LOSTDIR
struct direct lost_found_dir[] = {
{ LOSTFOUNDINO, sizeof (struct direct), 1, "." },
{ UFSROOTINO, sizeof (struct direct), 2, ".." },
{ 0, DIRBLKSIZ, 0, 0 },
};
#endif
char buf[MAXBSIZE];
static void
fsinit()
{
int i;
node.i_atime = mkfstime;
node.i_mtime = mkfstime;
node.i_ctime = mkfstime;
#ifdef LOSTDIR
(void) makedir(lost_found_dir, 2);
for (i = DIRBLKSIZ; i < sblock.fs_bsize; i += DIRBLKSIZ) {
bcopy(&lost_found_dir[2], &buf[i], DIRSIZ(&lost_found_dir[2]));
}
node.i_number = LOSTFOUNDINO;
node.i_smode = IFDIR | 0700;
node.i_nlink = 2;
node.i_size = sblock.fs_bsize;
node.i_db[0] = alloc((int)node.i_size, node.i_mode);
node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size));
IRANDOMIZE(&node.i_ic);
wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), (int)node.i_size, buf);
iput(&node);
#endif
node.i_number = UFSROOTINO;
node.i_mode = IFDIR | UMASK;
node.i_nlink = PREDEFDIR;
node.i_size = makedir(root_dir, PREDEFDIR);
node.i_db[0] = alloc(sblock.fs_fsize, node.i_mode);
node.i_blocks = btodb(fragroundup(&sblock, (int)node.i_size));
IRANDOMIZE(&node.i_ic);
wtfs(fsbtodb(&sblock, (uint64_t)node.i_db[0]), sblock.fs_fsize, buf);
iput(&node);
}
static int
makedir(struct direct *protodir, int entries)
{
char *cp;
int i;
ushort_t spcleft;
spcleft = DIRBLKSIZ;
for (cp = buf, i = 0; i < entries - 1; i++) {
protodir[i].d_reclen = DIRSIZ(&protodir[i]);
bcopy(&protodir[i], cp, protodir[i].d_reclen);
cp += protodir[i].d_reclen;
spcleft -= protodir[i].d_reclen;
}
protodir[i].d_reclen = spcleft;
bcopy(&protodir[i], cp, DIRSIZ(&protodir[i]));
return (DIRBLKSIZ);
}
static daddr32_t
alloc(int size, int mode)
{
int i, frag;
daddr32_t d;
rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
(char *)&acg);
if (acg.cg_magic != CG_MAGIC) {
(void) fprintf(stderr, gettext("cg 0: bad magic number\n"));
lockexit(32);
}
if (acg.cg_cs.cs_nbfree == 0) {
(void) fprintf(stderr,
gettext("first cylinder group ran out of space\n"));
lockexit(32);
}
for (d = 0; d < acg.cg_ndblk; d += sblock.fs_frag)
if (isblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag))
goto goth;
(void) fprintf(stderr,
gettext("internal error: can't find block in cyl 0\n"));
lockexit(32);
goth:
clrblock(&sblock, cg_blksfree(&acg), d / sblock.fs_frag);
acg.cg_cs.cs_nbfree--;
sblock.fs_cstotal.cs_nbfree--;
fscs[0].cs_nbfree--;
if (mode & IFDIR) {
acg.cg_cs.cs_ndir++;
sblock.fs_cstotal.cs_ndir++;
fscs[0].cs_ndir++;
}
cg_blktot(&acg)[cbtocylno(&sblock, d)]--;
cg_blks(&sblock, &acg, cbtocylno(&sblock, d))[cbtorpos(&sblock, d)]--;
if (size != sblock.fs_bsize) {
frag = howmany(size, sblock.fs_fsize);
fscs[0].cs_nffree += sblock.fs_frag - frag;
sblock.fs_cstotal.cs_nffree += sblock.fs_frag - frag;
acg.cg_cs.cs_nffree += sblock.fs_frag - frag;
acg.cg_frsum[sblock.fs_frag - frag]++;
for (i = frag; i < sblock.fs_frag; i++)
setbit(cg_blksfree(&acg), d + i);
}
wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
(char *)&acg);
return (d);
}
static void
iput(struct inode *ip)
{
struct dinode buf[MAXINOPB];
diskaddr_t d;
rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
(char *)&acg);
if (acg.cg_magic != CG_MAGIC) {
(void) fprintf(stderr, gettext("cg 0: bad magic number\n"));
lockexit(32);
}
acg.cg_cs.cs_nifree--;
setbit(cg_inosused(&acg), ip->i_number);
wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, 0)), sblock.fs_cgsize,
(char *)&acg);
sblock.fs_cstotal.cs_nifree--;
fscs[0].cs_nifree--;
if ((int)ip->i_number >= sblock.fs_ipg * sblock.fs_ncg) {
(void) fprintf(stderr,
gettext("fsinit: inode value out of range (%d).\n"),
ip->i_number);
lockexit(32);
}
d = fsbtodb(&sblock, (uint64_t)itod(&sblock, (int)ip->i_number));
rdfs(d, sblock.fs_bsize, (char *)buf);
buf[itoo(&sblock, (int)ip->i_number)].di_ic = ip->i_ic;
wtfs(d, sblock.fs_bsize, (char *)buf);
}
static char *
getbuf(bufhdr *bufhead, int size)
{
bufhdr *pbuf;
bufhdr *prev;
int i;
int buf_size, max_bufs;
if (bufhead->head == NULL) {
bufhdrsize = (sizeof (bufhdr) + 15) & ~15;
buf_size = (size + bufhdrsize + 15) & ~15;
max_bufs = MAXBUFMEM / buf_size;
if (max_bufs > MAXBUF)
max_bufs = MAXBUF;
pbuf = (bufhdr *)calloc(max_bufs, buf_size);
if (pbuf == NULL) {
perror("calloc");
lockexit(32);
}
bufhead->head = bufhead;
prev = bufhead;
for (i = 0; i < max_bufs; i++) {
pbuf->head = bufhead;
prev->next = pbuf;
prev = pbuf;
pbuf = (bufhdr *)((char *)pbuf + buf_size);
}
}
wait_for_write(NOBLOCK);
while (bufhead->next == NULL)
wait_for_write(BLOCK);
pbuf = bufhead->next;
bufhead->next = pbuf->next;
pbuf->next = NULL;
return ((char *)pbuf + bufhdrsize);
}
static void
freebuf(char *buf)
{
bufhdr *pbuf;
bufhdr *bufhead;
pbuf = (bufhdr *)(buf - bufhdrsize);
bufhead = pbuf->head;
pbuf->next = bufhead->next;
bufhead->next = pbuf;
}
static void
freetrans(aio_trans *transp)
{
if (transp->release == RELEASE)
freebuf(transp->buffer);
transp->next = results.trans;
results.trans = transp;
}
aio_trans *
wait_for_write(int block)
{
aio_trans *transp;
aio_result_t *resultp;
static struct timeval zero_wait = { 0, 0 };
sigset_t old_mask;
if (results.outstanding == 0)
return ((aio_trans *) 0);
block_sigint(&old_mask);
resultp = aiowait(block ? NULL : &zero_wait);
if (resultp == NULL ||
(resultp == (aio_result_t *)-1 && errno == EINVAL)) {
unblock_sigint(&old_mask);
return ((aio_trans *) 0);
}
results.outstanding--;
transp = (aio_trans *)resultp;
if (resultp->aio_return != transp->size) {
if (resultp->aio_return == -1) {
flush_writes();
wtfs_breakup(transp->bno, transp->size, transp->buffer);
} else {
(void) fprintf(stderr, gettext(
"short write (%d of %d bytes) on sector %lld\n"),
resultp->aio_return, transp->size,
transp->bno);
lockexit(32);
}
}
resultp->aio_return = 0;
freetrans(transp);
unblock_sigint(&old_mask);
return (transp);
}
static void
flush_writes(void)
{
while (wait_for_write(BLOCK))
;
}
aio_trans *
get_aiop()
{
int i;
aio_trans *transp;
aio_trans *prev;
if (!aio_inited) {
aio_inited = 1;
results.maxpend = 0;
results.outstanding = 0;
results.max = MAXAIO;
results.trans = (aio_trans *)calloc(results.max,
sizeof (aio_trans));
if (results.trans == NULL) {
perror("calloc");
lockexit(32);
}
prev = results.trans;
for (i = 1; i < results.max; i++) {
prev->next = &(results.trans[i]);
prev = prev->next;
}
}
wait_for_write(NOBLOCK);
while (results.trans == NULL)
wait_for_write(BLOCK);
transp = results.trans;
results.trans = results.trans->next;
transp->next = 0;
transp->resultbuf.aio_return = AIO_INPROGRESS;
return (transp);
}
static void
rdfs(diskaddr_t bno, int size, char *bf)
{
int n, saverr;
flush_writes();
if (llseek(fsi, (offset_t)bno * sectorsize, 0) < 0) {
saverr = errno;
(void) fprintf(stderr,
gettext("seek error on sector %lld: %s\n"),
bno, strerror(saverr));
lockexit(32);
}
n = read(fsi, bf, size);
if (n != size) {
saverr = errno;
if (n == -1)
(void) fprintf(stderr,
gettext("read error on sector %lld: %s\n"),
bno, strerror(saverr));
else
(void) fprintf(stderr, gettext(
"short read (%d of %d bytes) on sector %lld\n"),
n, size, bno);
lockexit(32);
}
}
static void
wtfs(diskaddr_t bno, int size, char *bf)
{
int n, saverr;
if (fso == -1)
return;
if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
saverr = errno;
(void) fprintf(stderr,
gettext("seek error on sector %lld: %s\n"),
bno, strerror(saverr));
lockexit(32);
}
if (Nflag)
return;
n = write(fso, bf, size);
if (n != size) {
saverr = errno;
if (n == -1)
(void) fprintf(stderr,
gettext("write error on sector %lld: %s\n"),
bno, strerror(saverr));
else
(void) fprintf(stderr, gettext(
"short write (%d of %d bytes) on sector %lld\n"),
n, size, bno);
lockexit(32);
}
}
static void
awtfs(diskaddr_t bno, int size, char *bf, int release)
{
int n;
aio_trans *transp;
sigset_t old_mask;
if (fso == -1)
return;
block_sigint(&old_mask);
if (Nflag) {
if (release == RELEASE)
freebuf(bf);
} else {
transp = get_aiop();
transp->bno = bno;
transp->buffer = bf;
transp->size = size;
transp->release = release;
n = aiowrite(fso, bf, size, (off_t)bno * sectorsize,
SEEK_SET, &transp->resultbuf);
if (n < 0) {
flush_writes();
wtfs_breakup(transp->bno, transp->size, transp->buffer);
freetrans(transp);
} else {
results.outstanding++;
if (results.outstanding > results.maxpend)
results.maxpend = results.outstanding;
}
}
unblock_sigint(&old_mask);
}
static void
wtfs_breakup(diskaddr_t bno, int size, char *bf)
{
int n, saverr;
int wsize;
int block_incr = sbsize / sectorsize;
if (size < sbsize)
wsize = size;
else
wsize = sbsize;
n = 0;
while (size) {
if (llseek(fso, (offset_t)bno * sectorsize, 0) < 0) {
saverr = errno;
(void) fprintf(stderr,
gettext("seek error on sector %lld: %s\n"),
bno, strerror(saverr));
lockexit(32);
}
n = write(fso, bf, wsize);
if (n == -1) {
saverr = errno;
(void) fprintf(stderr,
gettext("write error on sector %lld: %s\n"),
bno, strerror(saverr));
lockexit(32);
}
if (n != wsize) {
saverr = errno;
(void) fprintf(stderr, gettext(
"short write (%d of %d bytes) on sector %lld\n"),
n, size, bno);
lockexit(32);
}
bno += block_incr;
bf += wsize;
size -= wsize;
if (size < wsize)
wsize = size;
}
}
static int
isblock(struct fs *fs, unsigned char *cp, int h)
{
unsigned char mask;
switch (fs->fs_frag) {
case 8:
return (cp[h] == 0xff);
case 4:
mask = 0x0f << ((h & 0x1) << 2);
return ((cp[h >> 1] & mask) == mask);
case 2:
mask = 0x03 << ((h & 0x3) << 1);
return ((cp[h >> 2] & mask) == mask);
case 1:
mask = 0x01 << (h & 0x7);
return ((cp[h >> 3] & mask) == mask);
default:
(void) fprintf(stderr, "isblock bad fs_frag %d\n", fs->fs_frag);
return (0);
}
}
static void
clrblock(struct fs *fs, unsigned char *cp, int h)
{
switch ((fs)->fs_frag) {
case 8:
cp[h] = 0;
return;
case 4:
cp[h >> 1] &= ~(0x0f << ((h & 0x1) << 2));
return;
case 2:
cp[h >> 2] &= ~(0x03 << ((h & 0x3) << 1));
return;
case 1:
cp[h >> 3] &= ~(0x01 << (h & 0x7));
return;
default:
(void) fprintf(stderr,
gettext("clrblock: bad fs_frag value %d\n"), fs->fs_frag);
return;
}
}
static void
setblock(struct fs *fs, unsigned char *cp, int h)
{
switch (fs->fs_frag) {
case 8:
cp[h] = 0xff;
return;
case 4:
cp[h >> 1] |= (0x0f << ((h & 0x1) << 2));
return;
case 2:
cp[h >> 2] |= (0x03 << ((h & 0x3) << 1));
return;
case 1:
cp[h >> 3] |= (0x01 << (h & 0x7));
return;
default:
(void) fprintf(stderr,
gettext("setblock: bad fs_frag value %d\n"), fs->fs_frag);
return;
}
}
static void
usage(void)
{
(void) fprintf(stderr,
gettext("ufs usage: mkfs [-F FSType] [-V] [-m] [-o options] "
"special "
"size(sectors) \\ \n"));
(void) fprintf(stderr,
"[nsect "
"ntrack "
"bsize "
"fragsize "
"cpg "
"free "
"rps "
"nbpi "
"opt "
"apc "
"gap "
"nrpos "
"maxcontig "
"mtb]\n");
(void) fprintf(stderr,
gettext(" -m : dump fs cmd line used to make this partition\n"
" -V :print this command line and return\n"
" -o :ufs options: :nsect=%d,ntrack=%d,bsize=%d,fragsize=%d\n"
" -o :ufs options: :cgsize=%d,free=%d,rps=%d,nbpi=%d,opt=%c\n"
" -o :ufs options: :apc=%d,gap=%d,nrpos=%d,maxcontig=%d\n"
" -o :ufs options: :mtb=%c,calcsb,calcbinsb\n"
"NOTE that all -o suboptions: must be separated only by commas so as to\n"
"be parsed as a single argument\n"),
nsect, ntrack, bsize, fragsize, cpg, sblock.fs_minfree, rps,
nbpi, opt, apc, (rotdelay == -1) ? 0 : rotdelay,
sblock.fs_nrpos, maxcontig, mtb);
lockexit(32);
}
static void
dump_fscmd(char *fsys, int fsi)
{
int64_t used, bpcg, inospercg;
int64_t nbpi;
uint64_t nbytes64;
bzero((char *)&sblock, sizeof (sblock));
rdfs((diskaddr_t)SBLOCK, SBSIZE, (char *)&sblock);
if ((sblock.fs_magic != FS_MAGIC) &&
(sblock.fs_magic != MTB_UFS_MAGIC)) {
(void) fprintf(stderr, gettext(
"[not currently a valid file system - bad superblock]\n"));
lockexit(32);
}
if (sblock.fs_magic == FS_MAGIC &&
(sblock.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
sblock.fs_version != UFS_VERSION_MIN)) {
(void) fprintf(stderr, gettext(
"Unknown version of UFS format: %d\n"), sblock.fs_version);
lockexit(32);
}
if (sblock.fs_magic == MTB_UFS_MAGIC &&
(sblock.fs_version > MTB_UFS_VERSION_1 ||
sblock.fs_version < MTB_UFS_VERSION_MIN)) {
(void) fprintf(stderr, gettext(
"Unknown version of UFS format: %d\n"), sblock.fs_version);
lockexit(32);
}
bpcg = sblock.fs_spc * sectorsize;
inospercg = (int64_t)roundup(bpcg / sizeof (struct dinode),
INOPB(&sblock));
if (inospercg > MAXIpG(&sblock))
inospercg = MAXIpG(&sblock);
used = (int64_t)
(sblock.fs_iblkno + inospercg / INOPF(&sblock)) * NSPF(&sblock);
used *= sectorsize;
nbytes64 = (uint64_t)sblock.fs_cpg * bpcg - used;
nbpi = (int64_t)(nbytes64 / (sblock.fs_ipg));
(void) fprintf(stdout, gettext("mkfs -F ufs -o "), fsys);
(void) fprintf(stdout, "nsect=%d,ntrack=%d,",
sblock.fs_nsect, sblock.fs_ntrak);
(void) fprintf(stdout, "bsize=%d,fragsize=%d,cgsize=%d,free=%d,",
sblock.fs_bsize, sblock.fs_fsize, sblock.fs_cpg, sblock.fs_minfree);
(void) fprintf(stdout, "rps=%d,nbpi=%lld,opt=%c,apc=%d,gap=%d,",
sblock.fs_rps, nbpi, (sblock.fs_optim == FS_OPTSPACE) ? 's' : 't',
(sblock.fs_ntrak * sblock.fs_nsect) - sblock.fs_spc,
sblock.fs_rotdelay);
(void) fprintf(stdout, "nrpos=%d,maxcontig=%d,mtb=%c ",
sblock.fs_nrpos, sblock.fs_maxcontig,
((sblock.fs_magic == MTB_UFS_MAGIC) ? 'y' : 'n'));
(void) fprintf(stdout, "%s %lld\n", fsys,
fsbtodb(&sblock, sblock.fs_size));
bzero((char *)&sblock, sizeof (sblock));
}
static uint64_t
number(uint64_t d_value, char *param, int flags)
{
char *cs;
uint64_t n, t;
uint64_t cut = BIG / 10;
int minus = 0;
cs = string;
if (*cs == '-') {
minus = 1;
cs += 1;
}
if ((*cs < '0') || (*cs > '9')) {
goto bail_out;
}
n = 0;
while ((*cs >= '0') && (*cs <= '9') && (n <= cut)) {
n = n*10 + *cs++ - '0';
}
if (minus)
n = -n;
for (;;) {
switch (*cs++) {
case 'k':
if (flags & ALLOW_END_ONLY)
goto bail_out;
if (n > (BIG / 1024))
goto overflow;
n *= 1024;
continue;
case '*':
case 'x':
if (flags & ALLOW_END_ONLY)
goto bail_out;
string = cs;
t = number(d_value, param, flags);
if (n > (BIG / t))
goto overflow;
n *= t;
cs = string + 1;
case ',':
case '\0':
cs--;
string = cs;
return (n);
case '%':
if (flags & ALLOW_END_ONLY)
goto bail_out;
if (flags & ALLOW_PERCENT) {
flags &= ~ALLOW_PERCENT;
flags |= ALLOW_END_ONLY;
continue;
}
goto bail_out;
case 'm':
if (flags & ALLOW_END_ONLY)
goto bail_out;
if (flags & ALLOW_MS1) {
flags &= ~ALLOW_MS1;
flags |= ALLOW_MS2;
continue;
}
goto bail_out;
case 's':
if (flags & ALLOW_END_ONLY)
goto bail_out;
if (flags & ALLOW_MS2) {
flags &= ~ALLOW_MS2;
flags |= ALLOW_END_ONLY;
continue;
}
goto bail_out;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
overflow:
(void) fprintf(stderr,
gettext("mkfs: value for %s overflowed\n"),
param);
while ((*cs != '\0') && (*cs != ','))
cs++;
string = cs;
return (BIG);
default:
bail_out:
(void) fprintf(stderr, gettext(
"mkfs: bad numeric arg for %s: \"%s\"\n"),
param, string);
while ((*cs != '\0') && (*cs != ','))
cs++;
string = cs;
if (d_value != NO_DEFAULT) {
(void) fprintf(stderr,
gettext("mkfs: %s reset to default %lld\n"),
param, d_value);
return (d_value);
}
lockexit(2);
}
}
}
static int
match(char *s)
{
char *cs;
cs = string;
while (*cs++ == *s) {
if (*s++ == '\0') {
goto true;
}
}
if (*s != '\0') {
return (0);
}
true:
cs--;
string = cs;
return (1);
}
void
lockexit(int exitstatus)
{
if (Pflag) {
exit(exitstatus);
}
if (inlockexit == 0) {
inlockexit = 1;
flcg();
}
if (aio_inited) {
flush_writes();
}
if ((inlockexit == 1) && (!isbad)) {
inlockexit = 2;
ulockfs();
if (waslog) {
if (rl_log_control(fsys, _FIOLOGENABLE) != RL_SUCCESS) {
(void) fprintf(stderr, gettext(
"failed to re-enable logging\n"));
}
}
} else if (grow) {
if (isbad) {
(void) fprintf(stderr, gettext(
"Filesystem is currently inconsistent. It "
"must be repaired with fsck(8)\nbefore being "
"used. Use the following command to "
"do this:\n\n\tfsck %s\n\n"), fsys);
if (ismounted) {
(void) fprintf(stderr, gettext(
"You will be told that the filesystem "
"is already mounted, and asked if you\n"
"wish to continue. Answer `yes' to "
"this question.\n\n"));
}
(void) fprintf(stderr, gettext(
"One problem should be reported, that the summary "
"information is bad.\nYou will then be asked if it "
"should be salvaged. Answer `yes' to\nthis "
"question.\n\n"));
}
if (ismounted) {
(void) fprintf(stderr, gettext(
"The filesystem is currently mounted "
"read-only and write-locked. "));
if (isbad) {
(void) fprintf(stderr, gettext(
"After\nrunning fsck, unlock the "
"filesystem and "));
} else {
(void) fprintf(stderr, gettext(
"Unlock the filesystem\nand "));
}
(void) fprintf(stderr, gettext(
"re-enable writing with\nthe following "
"command:\n\n\tlockfs -u %s\n\n"), directory);
}
}
exit(exitstatus);
}
void
randomgeneration()
{
int i;
struct dinode *dp;
for (i = 0, dp = zino; i < sblock.fs_inopb; ++i, ++dp)
IRANDOMIZE(&dp->di_ic);
}
void
checksummarysize()
{
diskaddr_t dmax;
diskaddr_t dmin;
int64_t cg0frags;
int64_t cg0blocks;
int64_t maxncg;
int64_t maxfrags;
uint64_t fs_size;
uint64_t maxfs_blocks;
dmin = cgdmin(&sblock, 0);
dmax = cgbase(&sblock, 0) + sblock.fs_fpg;
fs_size = (grow) ? grow_fs_size : sblock.fs_size;
if (dmax > fs_size)
dmax = fs_size;
cg0frags = dmax - dmin;
cg0blocks = cg0frags / sblock.fs_frag;
cg0frags = cg0blocks * sblock.fs_frag;
maxncg = (longlong_t)cg0blocks *
(longlong_t)(sblock.fs_bsize / sizeof (struct csum));
maxfs_blocks = FS_MAX;
if (maxncg > ((longlong_t)maxfs_blocks / (longlong_t)sblock.fs_fpg) + 1)
maxncg = ((longlong_t)maxfs_blocks /
(longlong_t)sblock.fs_fpg) + 1;
maxfrags = maxncg * (longlong_t)sblock.fs_fpg;
if (maxfrags > maxfs_blocks)
maxfrags = maxfs_blocks;
if (test)
grow_sifrag = dmin + (cg0blocks * sblock.fs_frag);
if (testfrags == 0)
testfrags = cg0frags;
if (testforce)
if (testfrags > cg0frags) {
(void) fprintf(stderr,
gettext("Too many test frags (%lld); "
"try %lld\n"), testfrags, cg0frags);
lockexit(32);
}
if ((longlong_t)sblock.fs_size > maxfrags) {
(void) fprintf(stderr, gettext(
"Too many cylinder groups with %llu sectors;\n try "
"increasing cgsize, or decreasing fssize to %llu\n"),
fsbtodb(&sblock, (uint64_t)sblock.fs_size),
fsbtodb(&sblock, (uint64_t)maxfrags));
lockexit(32);
}
}
int
checksblock(struct fs sb, int proceed)
{
int err = 0;
char *errmsg;
if ((sb.fs_magic != FS_MAGIC) && (sb.fs_magic != MTB_UFS_MAGIC)) {
err = 1;
errmsg = gettext("Bad superblock; magic number wrong\n");
} else if ((sb.fs_magic == FS_MAGIC &&
(sb.fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
sb.fs_version != UFS_VERSION_MIN)) ||
(sb.fs_magic == MTB_UFS_MAGIC &&
(sb.fs_version > MTB_UFS_VERSION_1 ||
sb.fs_version < MTB_UFS_VERSION_MIN))) {
err = 2;
errmsg = gettext("Unrecognized version of UFS\n");
} else if (sb.fs_ncg < 1) {
err = 3;
errmsg = gettext("Bad superblock; ncg out of range\n");
} else if (sb.fs_cpg < 1) {
err = 4;
errmsg = gettext("Bad superblock; cpg out of range\n");
} else if (sb.fs_ncg * sb.fs_cpg < sb.fs_ncyl ||
(sb.fs_ncg - 1) * sb.fs_cpg >= sb.fs_ncyl) {
err = 5;
errmsg = gettext("Bad superblock; ncyl out of range\n");
} else if (sb.fs_sbsize <= 0 || sb.fs_sbsize > sb.fs_bsize) {
err = 6;
errmsg = gettext("Bad superblock; superblock size out of "
"range\n");
}
if (proceed) {
if (err) dbgprintf(("%s", errmsg));
return (err);
}
if (err) {
fprintf(stderr, "%s", errmsg);
lockexit(32);
}
return (32);
}
static void
logsetup(char *devstr)
{
void *buf, *ud_buf;
extent_block_t *ebp;
ml_unit_t *ul;
ml_odunit_t *ud;
if (sblock.fs_logbno == 0) {
islog = 0;
islogok = 0;
return;
} else {
islogok = 0;
if (rl_roll_log(devstr) != RL_SUCCESS)
return;
islog = 1;
if ((FSOKAY != (sblock.fs_state + sblock.fs_time)) ||
(sblock.fs_clean != FSLOG))
return;
buf = (void *)malloc(DEV_BSIZE);
if (buf == (void *) NULL)
return;
ud_buf = (void *)malloc(DEV_BSIZE);
if (ud_buf == (void *) NULL) {
free(buf);
return;
}
rdfs((diskaddr_t)logbtodb(&sblock, sblock.fs_logbno),
DEV_BSIZE, buf);
ebp = (extent_block_t *)buf;
if (ebp->type != LUFS_EXTENTS) {
free(buf);
free(ud_buf);
return;
}
rdfs((diskaddr_t)logbtodb(&sblock, ebp->extents[0].pbno),
DEV_BSIZE, ud_buf);
ud = (ml_odunit_t *)ud_buf;
ul = (ml_unit_t *)malloc(sizeof (*ul));
ul->un_ondisk = *ud;
if ((ul->un_chksum == ul->un_head_ident + ul->un_tail_ident) &&
(ul->un_version == LUFS_VERSION_LATEST) &&
(ul->un_badlog == 0))
islogok = 1;
free(ud_buf);
free(buf);
free(ul);
}
}
void
growinit(char *devstr)
{
int i;
char buf[DEV_BSIZE];
rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
(void) checksblock(sblock, 0);
if (sblock.fs_postblformat != FS_DYNAMICPOSTBLFMT) {
(void) fprintf(stderr,
gettext("old file system format; can't growfs\n"));
lockexit(32);
}
grow_fssize = fsbtodb(&sblock, (uint64_t)sblock.fs_size);
if (fssize_db < grow_fssize) {
(void) fprintf(stderr,
gettext("%lld sectors < current size of %lld sectors\n"),
fssize_db, grow_fssize);
lockexit(32);
}
if (mtb == 'y' && sblock.fs_magic != MTB_UFS_MAGIC) {
if (fssize_db >= SECTORS_PER_TERABYTE) {
(void) fprintf(stderr, gettext(
"File system was not set up with the multi-terabyte format.\n"));
(void) fprintf(stderr, gettext(
"Its size cannot be increased to a terabyte or more.\n"));
} else {
(void) fprintf(stderr, gettext(
"Cannot convert file system to multi-terabyte format.\n"));
}
lockexit(32);
}
logsetup(devstr);
if ((islog && !islogok) ||
((FSOKAY == (sblock.fs_state + sblock.fs_time)) &&
(sblock.fs_clean == FSLOG && !islog))) {
(void) fprintf(stderr,
gettext("logging device has errors; can't growfs\n"));
lockexit(32);
}
if (islog) {
if (rl_log_control(devstr, _FIOLOGDISABLE) != RL_SUCCESS) {
(void) fprintf(stderr, gettext(
"failed to disable logging\n"));
lockexit(32);
}
islog = 0;
waslog = 1;
}
if (ismounted)
wlockfs();
rdfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
rdfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf);
wtfs((diskaddr_t)fssize_db - 1, DEV_BSIZE, buf);
grow_fscs = read_summaryinfo(&sblock);
grow_fs_size = sblock.fs_size;
grow_fs_ncg = sblock.fs_ncg;
grow_fs_csaddr = (diskaddr_t)sblock.fs_csaddr;
grow_fs_cssize = sblock.fs_cssize;
if (FSOKAY == (sblock.fs_state + sblock.fs_time))
grow_fs_clean = sblock.fs_clean;
else
grow_fs_clean = FSBAD;
sblock.fs_clean = FSBAD;
sblock.fs_state = FSOKAY - sblock.fs_time;
isbad = 1;
wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
}
void
checkdev(char *rdev, char *bdev)
{
struct stat64 statarea;
if (stat64(bdev, &statarea) < 0) {
(void) fprintf(stderr, gettext("can't check mount point; "));
(void) fprintf(stderr, gettext("can't stat %s\n"), bdev);
lockexit(32);
}
if ((statarea.st_mode & S_IFMT) != S_IFBLK) {
(void) fprintf(stderr, gettext(
"can't check mount point; %s is not a block device\n"),
bdev);
lockexit(32);
}
if (stat64(rdev, &statarea) < 0) {
(void) fprintf(stderr, gettext("can't stat %s\n"), rdev);
lockexit(32);
}
if ((statarea.st_mode & S_IFMT) != S_IFCHR) {
(void) fprintf(stderr,
gettext("%s is not a character device\n"), rdev);
lockexit(32);
}
}
void
checkmount(struct mnttab *mntp, char *bdevname)
{
struct stat64 statdir;
struct stat64 statdev;
if (strcmp(bdevname, mntp->mnt_special) == 0) {
if (stat64(mntp->mnt_mountp, &statdir) == -1) {
(void) fprintf(stderr, gettext("can't stat %s\n"),
mntp->mnt_mountp);
lockexit(32);
}
if (stat64(mntp->mnt_special, &statdev) == -1) {
(void) fprintf(stderr, gettext("can't stat %s\n"),
mntp->mnt_special);
lockexit(32);
}
if (statdir.st_dev != statdev.st_rdev) {
(void) fprintf(stderr, gettext(
"%s is not mounted on %s; mnttab(5) wrong\n"),
mntp->mnt_special, mntp->mnt_mountp);
lockexit(32);
}
ismounted = 1;
if (directory) {
if (strcmp(mntp->mnt_mountp, directory) != 0) {
(void) fprintf(stderr,
gettext("%s is mounted on %s, not %s\n"),
bdevname, mntp->mnt_mountp, directory);
lockexit(32);
}
} else {
if (grow)
(void) fprintf(stderr, gettext(
"%s is mounted on %s; can't growfs\n"),
bdevname, mntp->mnt_mountp);
else
(void) fprintf(stderr,
gettext("%s is mounted, can't mkfs\n"),
bdevname);
lockexit(32);
}
}
}
struct dinode *dibuf = 0;
diskaddr_t difrag = 0;
struct dinode *
gdinode(ino_t ino)
{
if (dibuf == 0)
dibuf = (struct dinode *)malloc((unsigned)sblock.fs_bsize);
if (itod(&sblock, ino) != difrag) {
difrag = itod(&sblock, ino);
rdfs(fsbtodb(&sblock, (uint64_t)difrag), (int)sblock.fs_bsize,
(char *)dibuf);
}
return (dibuf + (ino % INOPB(&sblock)));
}
struct csfrag {
struct csfrag *next;
daddr32_t ofrag;
daddr32_t nfrag;
long cylno;
long frags;
long size;
ino_t ino;
long fixed;
};
struct csfrag *csfrag;
struct csfrag *csfragino;
struct csfrag *csfragfree;
daddr32_t maxcsfrag = 0;
daddr32_t mincsfrag = 0x7fffffff;
int
csfraginrange(daddr32_t frag)
{
return ((frag >= mincsfrag) && (frag <= maxcsfrag));
}
struct csfrag *
findcsfrag(daddr32_t frag, struct csfrag **cfap)
{
struct csfrag *cfp;
if (!csfraginrange(frag))
return (NULL);
for (cfp = *cfap; cfp; cfp = cfp->next)
if (cfp->ofrag == frag)
return (cfp);
return (NULL);
}
void
checkindirect(ino_t ino, daddr32_t *fragsp, daddr32_t frag, int level)
{
int i;
int ne = sblock.fs_bsize / sizeof (daddr32_t);
daddr32_t fsb[MAXBSIZE / sizeof (daddr32_t)];
if (frag == 0)
return;
rdfs(fsbtodb(&sblock, frag), (int)sblock.fs_bsize,
(char *)fsb);
checkdirect(ino, fragsp, fsb, sblock.fs_bsize / sizeof (daddr32_t));
if (level)
for (i = 0; i < ne && *fragsp; ++i)
checkindirect(ino, fragsp, fsb[i], level-1);
}
void
addcsfrag(ino_t ino, daddr32_t frag, struct csfrag **cfap)
{
struct csfrag *cfp, *curr, *prev;
if (frag > maxcsfrag)
maxcsfrag = frag;
if (frag < mincsfrag)
mincsfrag = frag;
if (ino && (frag % sblock.fs_frag))
for (cfp = *cfap; cfp; cfp = cfp->next) {
if (ino != cfp->ino)
continue;
if (frag != cfp->ofrag + cfp->frags)
continue;
cfp->frags++;
cfp->size += sblock.fs_fsize;
return;
}
cfp = (struct csfrag *)calloc(1, sizeof (struct csfrag));
cfp->ino = ino;
cfp->ofrag = frag;
cfp->frags = 1;
cfp->size = sblock.fs_fsize;
for (prev = NULL, curr = *cfap; curr != NULL;
prev = curr, curr = curr->next) {
if (frag < curr->ofrag) {
cfp->next = curr;
if (prev)
prev->next = cfp;
else
*cfap = cfp;
break;
}
if (curr->next == NULL) {
curr->next = cfp;
break;
}
}
if (*cfap == NULL)
*cfap = cfp;
}
void
delcsfrag(daddr32_t frag, struct csfrag **cfap)
{
struct csfrag *cfp;
struct csfrag **cfpp;
for (cfpp = cfap; *cfpp; cfpp = &(*cfpp)->next) {
if (frag == (*cfpp)->ofrag) {
cfp = *cfpp;
*cfpp = (*cfpp)->next;
free((char *)cfp);
return;
}
}
}
void
checkdirect(ino_t ino, daddr32_t *fragsp, daddr32_t *db, int ne)
{
int i;
int j;
int found;
diskaddr_t frag;
for (i = 0; i < ne && *fragsp; ++i) {
if ((frag = *db++) != 0) {
found = 0;
for (j = 0; j < sblock.fs_frag && *fragsp; ++j) {
if (found || (found = csfraginrange(frag))) {
addcsfrag(ino, frag, &csfragino);
delcsfrag(frag, &csfrag);
}
++frag;
--(*fragsp);
}
}
}
}
void
findcsfragino()
{
int i;
int j;
daddr32_t frags;
struct dinode *dp;
for (i = UFSROOTINO; i < grow_fs_ncg*sblock.fs_ipg && csfrag; ++i) {
dp = gdinode((ino_t)i);
switch (dp->di_mode & IFMT) {
case IFSHAD :
case IFLNK :
case IFDIR :
case IFREG : break;
default : continue;
}
frags = dbtofsb(&sblock, dp->di_blocks);
checkdirect((ino_t)i, &frags, &dp->di_db[0], NDADDR+NIADDR);
for (j = 0; j < NIADDR && frags; ++j) {
if (dp->di_ib[j] < 0 && dp->di_ib[j] != UFS_HOLE)
checkindirect((ino_t)i, &frags,
-(dp->di_ib[j]), j);
else
checkindirect((ino_t)i, &frags,
dp->di_ib[j], j);
}
}
}
void
fixindirect(daddr32_t frag, int level)
{
int i;
int ne = sblock.fs_bsize / sizeof (daddr32_t);
daddr32_t fsb[MAXBSIZE / sizeof (daddr32_t)];
if (frag == 0)
return;
rdfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize,
(char *)fsb);
fixdirect((caddr_t)fsb, frag, fsb, ne);
if (level)
for (i = 0; i < ne; ++i)
fixindirect(fsb[i], level-1);
}
void
fixdirect(caddr_t bp, daddr32_t frag, daddr32_t *db, int ne)
{
int i;
struct csfrag *cfp;
for (i = 0; i < ne; ++i, ++db) {
if (*db == 0)
continue;
if ((cfp = findcsfrag(*db, &csfragino)) == NULL)
continue;
*db = cfp->nfrag;
cfp->fixed = 1;
wtfs(fsbtodb(&sblock, (uint64_t)frag), (int)sblock.fs_bsize,
bp);
}
}
void
fixcsfragino()
{
int i;
struct dinode *dp;
struct csfrag *cfp;
for (cfp = csfragino; cfp; cfp = cfp->next) {
if (cfp->fixed)
continue;
dp = gdinode((ino_t)cfp->ino);
fixdirect((caddr_t)dibuf, difrag, dp->di_db, NDADDR+NIADDR);
for (i = 0; i < NIADDR; ++i)
fixindirect(dp->di_ib[i], i);
}
}
static struct csum *
read_summaryinfo(struct fs *fsp)
{
struct csum *csp;
int i;
if ((csp = malloc((size_t)fsp->fs_cssize)) == NULL) {
(void) fprintf(stderr, gettext("cannot create csum list,"
" not enough memory\n"));
exit(32);
}
for (i = 0; i < fsp->fs_cssize; i += fsp->fs_bsize) {
rdfs(fsbtodb(fsp,
(uint64_t)(fsp->fs_csaddr + numfrags(fsp, i))),
(int)(fsp->fs_cssize - i < fsp->fs_bsize ?
fsp->fs_cssize - i : fsp->fs_bsize), ((caddr_t)csp) + i);
}
return (csp);
}
int64_t
checkfragallocated(daddr32_t frag)
{
struct csfrag *cfp;
for (cfp = csfragfree; cfp != NULL && frag >= cfp->ofrag;
cfp = cfp->next) {
if (frag == cfp->ofrag)
return (1);
}
for (cfp = csfragino; cfp != NULL && frag >= cfp->ofrag;
cfp = cfp->next) {
if (frag == cfp->ofrag && cfp->nfrag != 0)
return (cfp->frags);
}
return (0);
}
diskaddr_t
probe_summaryinfo()
{
int64_t growth_csum_frags = 0;
int64_t growth_fs_frags = 0;
int64_t new_fs_cssize;
int64_t new_fs_ncg;
int64_t spare_csum;
daddr32_t oldfrag_daddr;
daddr32_t newfrag_daddr;
daddr32_t daddr;
int i;
rdfs((diskaddr_t)(SBOFF / sectorsize), (int)sbsize, (char *)&sblock);
(void) checksblock(sblock, 0);
fscs = read_summaryinfo(&sblock);
oldfrag_daddr = howmany(sblock.fs_cssize, sblock.fs_fsize) +
sblock.fs_csaddr;
new_fs_ncg = howmany(dbtofsb(&sblock, fssize_db), sblock.fs_fpg);
new_fs_cssize = fragroundup(&sblock, new_fs_ncg * sizeof (struct csum));
newfrag_daddr = howmany(new_fs_cssize, sblock.fs_fsize) +
sblock.fs_csaddr;
for (daddr = oldfrag_daddr; daddr < newfrag_daddr; daddr++)
addcsfrag((ino_t)0, daddr, &csfrag);
findcsfragfree();
alloccsfragfree();
grow_fs_ncg = sblock.fs_ncg;
findcsfragino();
alloccsfragino();
if (notenoughspace()) {
int64_t tmp_frags;
for (daddr = oldfrag_daddr; daddr < newfrag_daddr;
daddr += tmp_frags) {
if ((tmp_frags = checkfragallocated(daddr)) > 0)
growth_csum_frags += tmp_frags;
else
break;
}
} else {
return (fssize_db);
}
growth_fs_frags = howmany(sblock.fs_fsize, sizeof (struct csum)) *
growth_csum_frags * sblock.fs_fpg;
rdcg(sblock.fs_ncg - 1);
growth_fs_frags += sblock.fs_fpg - acg.cg_ndblk;
spare_csum = howmany(sblock.fs_cssize, sizeof (struct csum)) -
sblock.fs_ncg;
if (spare_csum > 0)
growth_fs_frags += spare_csum * sblock.fs_fpg;
if (growth_fs_frags > 0) {
diskaddr_t sect;
sect = (sblock.fs_size + growth_fs_frags) * sblock.fs_nspf;
return ((sect > fssize_db) ? fssize_db : sect);
}
return (0);
}
void
extendsummaryinfo()
{
int64_t i;
int localtest = test;
int64_t frags;
daddr32_t oldfrag;
daddr32_t newfrag;
if (Nflag)
return;
again:
flcg();
if (grow_fs_cssize == sblock.fs_cssize)
if (!localtest)
return;
oldfrag = howmany(grow_fs_cssize, sblock.fs_fsize) + grow_fs_csaddr;
newfrag = howmany(sblock.fs_cssize, sblock.fs_fsize) + grow_fs_csaddr;
for (i = oldfrag, frags = 0; i < newfrag; ++i, ++frags)
addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag);
sblock.fs_dsize -= (newfrag - oldfrag);
if (localtest)
for (i = newfrag; i < grow_sifrag; ++i) {
if (frags >= testfrags)
break;
frags++;
addcsfrag((ino_t)0, (diskaddr_t)i, &csfrag);
}
findcsfragfree();
findcsfragino();
if (csfrag) {
isbad = 1;
lockexit(32);
}
alloccsfragfree();
alloccsfragino();
if (notenoughspace()) {
unalloccsfragfree();
unalloccsfragino();
if (localtest && !testforce) {
localtest = 0;
goto again;
}
(void) fprintf(stderr, gettext("Not enough free space\n"));
lockexit(NOTENOUGHSPACE);
}
copycsfragino();
fixcsfragino();
rdcg((long)0);
for (i = newfrag; i <= maxcsfrag; ++i)
setbit(cg_blksfree(&acg), i-cgbase(&sblock, 0));
wtcg();
flcg();
}
int
notenoughspace()
{
struct csfrag *cfp;
for (cfp = csfragino; cfp; cfp = cfp->next)
if (cfp->nfrag == 0)
return (1);
return (0);
}
void
unalloccsfragino()
{
struct csfrag *cfp;
while ((cfp = csfragino) != NULL) {
if (cfp->nfrag)
freefrags(cfp->nfrag, cfp->frags, cfp->cylno);
delcsfrag(cfp->ofrag, &csfragino);
}
}
void
unalloccsfragfree()
{
struct csfrag *cfp;
while ((cfp = csfragfree) != NULL) {
freefrags(cfp->ofrag, cfp->frags, cfp->cylno);
delcsfrag(cfp->ofrag, &csfragfree);
}
}
void
findcsfragfree()
{
struct csfrag *cfp;
struct csfrag *cfpnext;
rdcg((long)0);
for (cfp = csfrag; cfp; cfp = cfpnext) {
cfpnext = cfp->next;
if (isset(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0))) {
addcsfrag(cfp->ino, cfp->ofrag, &csfragfree);
delcsfrag(cfp->ofrag, &csfrag);
}
}
}
void
copycsfragino()
{
struct csfrag *cfp;
char buf[MAXBSIZE];
for (cfp = csfragino; cfp; cfp = cfp->next) {
rdfs(fsbtodb(&sblock, (uint64_t)cfp->ofrag), (int)cfp->size,
buf);
wtfs(fsbtodb(&sblock, (uint64_t)cfp->nfrag), (int)cfp->size,
buf);
}
}
long curcylno = -1;
int cylnodirty = 0;
void
rdcg(long cylno)
{
if (cylno != curcylno) {
flcg();
curcylno = cylno;
rdfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)),
(int)sblock.fs_cgsize, (char *)&acg);
}
}
void
flcg()
{
if (cylnodirty) {
if (debug && Pflag) {
(void) fprintf(stderr,
"Assert: cylnodirty set in probe mode\n");
return;
}
resetallocinfo();
wtfs(fsbtodb(&sblock, (uint64_t)cgtod(&sblock, curcylno)),
(int)sblock.fs_cgsize, (char *)&acg);
cylnodirty = 0;
}
curcylno = -1;
}
void
wtcg()
{
if (!Pflag) {
cylnodirty = 1;
}
}
void
allocfrags(long frags, daddr32_t *fragp, long *cylnop)
{
int i;
int j;
long bits;
long bit;
for (i = 0, *fragp = 0; i < grow_fs_ncg; ++i) {
if (((fscs+i)->cs_nffree < frags) && ((fscs+i)->cs_nbfree == 0))
continue;
rdcg((long)i);
bit = bits = 0;
while (findfreerange(&bit, &bits)) {
if (frags <= bits) {
for (j = 0; j < frags; ++j)
clrbit(cg_blksfree(&acg), bit+j);
wtcg();
*cylnop = i;
*fragp = bit + cgbase(&sblock, i);
return;
}
bit += bits;
}
}
}
void
alloccsfragino()
{
struct csfrag *cfp;
for (cfp = csfragino; cfp; cfp = cfp->next) {
allocfrags(cfp->frags, &cfp->nfrag, &cfp->cylno);
if (cfp->nfrag == 0)
break;
}
}
void
alloccsfragfree()
{
struct csfrag *cfp;
rdcg((long)0);
for (cfp = csfragfree; cfp; cfp = cfp->next)
clrbit(cg_blksfree(&acg), cfp->ofrag - cgbase(&sblock, 0));
wtcg();
}
void
freefrags(daddr32_t frag, long frags, long cylno)
{
int i;
rdcg(cylno);
for (i = 0; i < frags; ++i) {
setbit(cg_blksfree(&acg), (frag+i) - cgbase(&sblock, cylno));
}
wtcg();
}
int
findfreerange(long *bitp, long *bitsp)
{
long bit;
for (bit = *bitp, *bitsp = 0; bit < acg.cg_ndblk; ++bit)
if (isset(cg_blksfree(&acg), bit))
break;
if (bit >= acg.cg_ndblk)
return (0);
*bitp = bit;
*bitsp = 1;
for (++bit; bit < acg.cg_ndblk; ++bit, ++(*bitsp)) {
if ((bit % sblock.fs_frag) == 0)
break;
if (isclr(cg_blksfree(&acg), bit))
break;
}
return (1);
}
void
resetallocinfo()
{
long cno;
long bit;
long bits;
sblock.fs_cstotal.cs_nffree -= acg.cg_cs.cs_nffree;
sblock.fs_cstotal.cs_nbfree -= acg.cg_cs.cs_nbfree;
acg.cg_cs.cs_nffree = 0;
acg.cg_cs.cs_nbfree = 0;
bzero((caddr_t)acg.cg_frsum, sizeof (acg.cg_frsum));
bzero((caddr_t)cg_blktot(&acg), (int)(acg.cg_iusedoff-acg.cg_btotoff));
bit = bits = 0;
while (findfreerange(&bit, &bits)) {
if (bits == sblock.fs_frag) {
acg.cg_cs.cs_nbfree++;
cno = cbtocylno(&sblock, bit);
cg_blktot(&acg)[cno]++;
cg_blks(&sblock, &acg, cno)[cbtorpos(&sblock, bit)]++;
} else {
acg.cg_cs.cs_nffree += bits;
acg.cg_frsum[bits]++;
}
bit += bits;
}
*(fscs + acg.cg_cgx) = acg.cg_cs;
sblock.fs_cstotal.cs_nffree += acg.cg_cs.cs_nffree;
sblock.fs_cstotal.cs_nbfree += acg.cg_cs.cs_nbfree;
}
void
extendcg(long cylno)
{
int i;
diskaddr_t dupper;
diskaddr_t cbase;
diskaddr_t dmax;
flcg();
rdcg(cylno);
dupper = acg.cg_ndblk;
if (cylno == sblock.fs_ncg - 1)
acg.cg_ncyl = sblock.fs_ncyl - (sblock.fs_cpg * cylno);
else
acg.cg_ncyl = sblock.fs_cpg;
cbase = cgbase(&sblock, cylno);
dmax = cbase + sblock.fs_fpg;
if (dmax > sblock.fs_size)
dmax = sblock.fs_size;
acg.cg_ndblk = dmax - cbase;
for (i = dupper; i < acg.cg_ndblk; ++i)
setbit(cg_blksfree(&acg), i);
sblock.fs_dsize += (acg.cg_ndblk - dupper);
wtcg();
flcg();
}
struct lockfs lockfs;
int lockfd;
int islocked;
int lockfskey;
char lockfscomment[128];
void
ulockfs()
{
if (islocked == 0)
return;
lockfs.lf_flags = LOCKFS_MOD;
if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) {
perror(directory);
lockexit(32);
}
if (LOCKFS_IS_MOD(&lockfs)) {
(void) fprintf(stderr,
gettext("FILE SYSTEM CHANGED DURING GROWFS!\n"));
(void) fprintf(stderr,
gettext(" See lockfs(8), umount(8), and fsck(8)\n"));
lockexit(32);
}
lockfs.lf_lock = LOCKFS_ULOCK;
lockfs.lf_flags = 0;
lockfs.lf_key = lockfskey;
clockfs();
if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) {
perror(directory);
lockexit(32);
}
}
void
wlockfs()
{
if (Nflag)
return;
if ((lockfd = open64(directory, O_RDONLY)) == -1) {
perror(directory);
lockexit(32);
}
if (ioctl(lockfd, _FIOLFSS, &lockfs) == -1) {
perror(directory);
lockexit(32);
}
if (lockfs.lf_lock != LOCKFS_WLOCK) {
lockfs.lf_lock = LOCKFS_WLOCK;
lockfs.lf_flags = 0;
lockfs.lf_key = 0;
clockfs();
if (ioctl(lockfd, _FIOLFS, &lockfs) == -1) {
perror(directory);
lockexit(32);
}
}
islocked = 1;
lockfskey = lockfs.lf_key;
}
void
clockfs()
{
time_t t;
char *ct;
(void) time(&t);
ct = ctime(&t);
ct[strlen(ct)-1] = '\0';
(void) sprintf(lockfscomment, "%s -- mkfs pid %d", ct, getpid());
lockfs.lf_comlen = strlen(lockfscomment)+1;
lockfs.lf_comment = lockfscomment;
}
void
wtsb()
{
long i;
for (i = 0; i < sblock.fs_cssize; i += sblock.fs_bsize)
wtfs(fsbtodb(&sblock, (uint64_t)(sblock.fs_csaddr +
numfrags(&sblock, i))),
(int)(sblock.fs_cssize - i < sblock.fs_bsize ?
sblock.fs_cssize - i : sblock.fs_bsize),
((char *)fscs) + i);
sblock.fs_time = mkfstime;
wtfs((diskaddr_t)(SBOFF / sectorsize), sbsize, (char *)&sblock);
}
static char
checkopt(char *optim)
{
char opt;
int limit = strcspn(optim, ",");
switch (limit) {
case 0:
(void) fprintf(stderr, gettext(
"mkfs: missing optimization flag reset to `t' (time)\n"));
opt = 't';
break;
case 1:
opt = *optim;
if ((opt != 's') && (opt != 't')) {
(void) fprintf(stderr, gettext(
"mkfs: bad optimization value `%c' reset to `t' (time)\n"),
opt);
opt = 't';
}
break;
default:
(void) fprintf(stderr, gettext(
"mkfs: bad optimization value `%*.*s' reset to `t' (time)\n"),
limit, limit, optim);
opt = 't';
break;
}
string += limit;
return (opt);
}
static char
checkmtb(char *mtbarg)
{
char mtbc;
int limit = strcspn(mtbarg, ",");
switch (limit) {
case 0:
(void) fprintf(stderr, gettext(
"mkfs: missing mtb flag reset to `n' (no mtb support)\n"));
mtbc = 'n';
break;
case 1:
mtbc = tolower(*mtbarg);
if ((mtbc != 'y') && (mtbc != 'n')) {
(void) fprintf(stderr, gettext(
"mkfs: bad mtb value `%c' reset to `n' (no mtb support)\n"),
mtbc);
mtbc = 'n';
}
break;
default:
(void) fprintf(stderr, gettext(
"mkfs: bad mtb value `%*.*s' reset to `n' (no mtb support)\n"),
limit, limit, mtbarg);
opt = 'n';
break;
}
string += limit;
return (mtbc);
}
static void
range_check(long *varp, char *name, long minimum, long maximum,
long def_val, int user_supplied)
{
dbgprintf(("DeBuG %s : %ld (%ld %ld %ld)\n",
name, *varp, minimum, maximum, def_val));
if ((*varp < minimum) || (*varp > maximum)) {
if (user_supplied != RC_DEFAULT) {
(void) fprintf(stderr, gettext(
"mkfs: bad value for %s: %ld must be between %ld and %ld\n"),
name, *varp, minimum, maximum);
}
if (def_val != NO_DEFAULT) {
if (user_supplied) {
(void) fprintf(stderr,
gettext("mkfs: %s reset to default %ld\n"),
name, def_val);
}
*varp = def_val;
dbgprintf(("DeBuG %s : %ld\n", name, *varp));
return;
}
lockexit(2);
}
}
static void
range_check_64(uint64_t *varp, char *name, uint64_t minimum, uint64_t maximum,
uint64_t def_val, int user_supplied)
{
if ((*varp < minimum) || (*varp > maximum)) {
if (user_supplied != RC_DEFAULT) {
(void) fprintf(stderr, gettext(
"mkfs: bad value for %s: %lld must be between %lld and %lld\n"),
name, *varp, minimum, maximum);
}
if (def_val != NO_DEFAULT) {
if (user_supplied) {
(void) fprintf(stderr,
gettext("mkfs: %s reset to default %lld\n"),
name, def_val);
}
*varp = def_val;
return;
}
lockexit(2);
}
}
static void
block_sigint(sigset_t *old_mask)
{
sigset_t block_mask;
if (sigemptyset(&block_mask) < 0) {
fprintf(stderr, gettext("Could not clear signal mask\n"));
lockexit(3);
}
if (sigaddset(&block_mask, SIGINT) < 0) {
fprintf(stderr, gettext("Could not set signal mask\n"));
lockexit(3);
}
if (sigprocmask(SIG_BLOCK, &block_mask, old_mask) < 0) {
fprintf(stderr, gettext("Could not block SIGINT\n"));
lockexit(3);
}
}
static void
unblock_sigint(sigset_t *old_mask)
{
if (sigprocmask(SIG_UNBLOCK, old_mask, (sigset_t *)NULL) < 0) {
fprintf(stderr, gettext("Could not restore signal mask\n"));
lockexit(3);
}
}
static void
recover_from_sigint(int signum)
{
if (fso > -1) {
if ((Nflag != 0) || confirm_abort()) {
lockexit(4);
}
}
}
static int
confirm_abort(void)
{
char line[80];
printf(gettext("\n\nAborting at this point will leave the filesystem "
"in an inconsistent\nstate. If you do choose to stop, "
"you will be given instructions on how to\nrecover "
"the filesystem. Do you wish to cancel the filesystem "
"grow\noperation (y/n)?"));
if (getaline(stdin, line, sizeof (line)) == EOF)
line[0] = 'y';
printf("\n");
if (line[0] == 'y' || line[0] == 'Y')
return (1);
else {
return (0);
}
}
static int
getaline(FILE *fp, char *loc, int maxlen)
{
int n;
char *p, *lastloc;
p = loc;
lastloc = &p[maxlen-1];
while ((n = getc(fp)) != '\n') {
if (n == EOF)
return (EOF);
if (!isspace(n) && p < lastloc)
*p++ = n;
}
*p = 0;
return (p - loc);
}
static long
compute_maxcpg(long bsize, long fragsize, long nbpi, long nrpos, long spc)
{
int maxcpg_given_nbpi;
int maxcpg_given_fragsize;
int spf;
int inode_divisor;
int old_max_given_frag = 0;
int old_max_given_nbpi = INT_MAX;
spf = fragsize / DEV_BSIZE;
inode_divisor = 3;
while (1) {
maxcpg_given_nbpi =
(((int64_t)(MAXIpG_B(bsize, inode_divisor))) * nbpi) /
(DEV_BSIZE * ((int64_t)spc));
maxcpg_given_fragsize =
(bsize - (sizeof (struct cg)) - (bsize / inode_divisor)) /
(sizeof (long) + nrpos * sizeof (short) +
(spc / spf) / NBBY);
if (maxcpg_given_fragsize >= maxcpg_given_nbpi)
return (maxcpg_given_nbpi);
if (!(maxcpg_given_nbpi < old_max_given_nbpi) &&
!(maxcpg_given_fragsize > old_max_given_frag))
return (MIN(old_max_given_nbpi, old_max_given_frag));
if (maxcpg_given_nbpi > old_max_given_nbpi ||
maxcpg_given_fragsize < old_max_given_frag)
return (MIN(old_max_given_nbpi, old_max_given_frag));
old_max_given_nbpi = maxcpg_given_nbpi;
old_max_given_frag = maxcpg_given_fragsize;
inode_divisor++;
}
}
static int
in_64bit_mode(void)
{
char *cmd = "/usr/bin/isainfo -b";
char buf[BUFSIZ];
FILE *ptr;
int retval = 0;
putenv("IFS= \t");
if ((ptr = popen(cmd, "r")) != NULL) {
if (fgets(buf, BUFSIZ, ptr) != NULL &&
strncmp(buf, "64", 2) == 0)
retval = 1;
(void) pclose(ptr);
}
return (retval);
}
static int
validate_size(int fd, diskaddr_t size)
{
char buf[DEV_BSIZE];
int rc;
if ((llseek(fd, (offset_t)((size - 1) * DEV_BSIZE), SEEK_SET) == -1) ||
(read(fd, buf, DEV_BSIZE)) != DEV_BSIZE)
rc = 0;
else
rc = 1;
return (rc);
}
static void
dump_sblock(void)
{
int row, column, pending, written;
caddr_t source;
if (Rflag) {
pending = sizeof (sblock);
source = (caddr_t)&sblock;
do {
written = write(fileno(stdout), source, pending);
pending -= written;
source += written;
} while ((pending > 0) && (written > 0));
if (written < 0) {
perror(gettext("Binary dump of superblock failed"));
lockexit(1);
}
return;
} else {
printf("0x%x sblock.fs_link\n", sblock.fs_link);
printf("0x%x sblock.fs_rolled\n", sblock.fs_rolled);
printf("0x%x sblock.fs_sblkno\n", sblock.fs_sblkno);
printf("0x%x sblock.fs_cblkno\n", sblock.fs_cblkno);
printf("0x%x sblock.fs_iblkno\n", sblock.fs_iblkno);
printf("0x%x sblock.fs_dblkno\n", sblock.fs_dblkno);
printf("0x%x sblock.fs_cgoffset\n", sblock.fs_cgoffset);
printf("0x%x sblock.fs_cgmask\n", sblock.fs_cgmask);
printf("0x%x sblock.fs_time\n", sblock.fs_time);
printf("0x%x sblock.fs_size\n", sblock.fs_size);
printf("0x%x sblock.fs_dsize\n", sblock.fs_dsize);
printf("0x%x sblock.fs_ncg\n", sblock.fs_ncg);
printf("0x%x sblock.fs_bsize\n", sblock.fs_bsize);
printf("0x%x sblock.fs_fsize\n", sblock.fs_fsize);
printf("0x%x sblock.fs_frag\n", sblock.fs_frag);
printf("0x%x sblock.fs_minfree\n", sblock.fs_minfree);
printf("0x%x sblock.fs_rotdelay\n", sblock.fs_rotdelay);
printf("0x%x sblock.fs_rps\n", sblock.fs_rps);
printf("0x%x sblock.fs_bmask\n", sblock.fs_bmask);
printf("0x%x sblock.fs_fmask\n", sblock.fs_fmask);
printf("0x%x sblock.fs_bshift\n", sblock.fs_bshift);
printf("0x%x sblock.fs_fshift\n", sblock.fs_fshift);
printf("0x%x sblock.fs_maxcontig\n", sblock.fs_maxcontig);
printf("0x%x sblock.fs_maxbpg\n", sblock.fs_maxbpg);
printf("0x%x sblock.fs_fragshift\n", sblock.fs_fragshift);
printf("0x%x sblock.fs_fsbtodb\n", sblock.fs_fsbtodb);
printf("0x%x sblock.fs_sbsize\n", sblock.fs_sbsize);
printf("0x%x sblock.fs_csmask\n", sblock.fs_csmask);
printf("0x%x sblock.fs_csshift\n", sblock.fs_csshift);
printf("0x%x sblock.fs_nindir\n", sblock.fs_nindir);
printf("0x%x sblock.fs_inopb\n", sblock.fs_inopb);
printf("0x%x sblock.fs_nspf\n", sblock.fs_nspf);
printf("0x%x sblock.fs_optim\n", sblock.fs_optim);
#ifdef _LITTLE_ENDIAN
printf("0x%x sblock.fs_state\n", sblock.fs_state);
#else
printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect);
#endif
printf("0x%x sblock.fs_si\n", sblock.fs_si);
printf("0x%x sblock.fs_trackskew\n", sblock.fs_trackskew);
printf("0x%x sblock.fs_id[0]\n", sblock.fs_id[0]);
printf("0x%x sblock.fs_id[1]\n", sblock.fs_id[1]);
printf("0x%x sblock.fs_csaddr\n", sblock.fs_csaddr);
printf("0x%x sblock.fs_cssize\n", sblock.fs_cssize);
printf("0x%x sblock.fs_cgsize\n", sblock.fs_cgsize);
printf("0x%x sblock.fs_ntrak\n", sblock.fs_ntrak);
printf("0x%x sblock.fs_nsect\n", sblock.fs_nsect);
printf("0x%x sblock.fs_spc\n", sblock.fs_spc);
printf("0x%x sblock.fs_ncyl\n", sblock.fs_ncyl);
printf("0x%x sblock.fs_cpg\n", sblock.fs_cpg);
printf("0x%x sblock.fs_ipg\n", sblock.fs_ipg);
printf("0x%x sblock.fs_fpg\n", sblock.fs_fpg);
printf("0x%x sblock.fs_cstotal\n", sblock.fs_cstotal);
printf("0x%x sblock.fs_fmod\n", sblock.fs_fmod);
printf("0x%x sblock.fs_clean\n", sblock.fs_clean);
printf("0x%x sblock.fs_ronly\n", sblock.fs_ronly);
printf("0x%x sblock.fs_flags\n", sblock.fs_flags);
printf("0x%x sblock.fs_fsmnt\n", sblock.fs_fsmnt);
printf("0x%x sblock.fs_cgrotor\n", sblock.fs_cgrotor);
printf("0x%x sblock.fs_u.fs_csp\n", sblock.fs_u.fs_csp);
printf("0x%x sblock.fs_cpc\n", sblock.fs_cpc);
for (row = 0; row < 16; row++) {
for (column = 0; column < 8; column++) {
printf("0x%x sblock.fs_opostbl[%d][%d]\n",
sblock.fs_opostbl[row][column],
row, column);
}
}
for (row = 0; row < 51; row++) {
printf("0x%x sblock.fs_sparecon[%d]\n",
sblock.fs_sparecon[row], row);
}
printf("0x%x sblock.fs_version\n", sblock.fs_version);
printf("0x%x sblock.fs_logbno\n", sblock.fs_logbno);
printf("0x%x sblock.fs_reclaim\n", sblock.fs_reclaim);
printf("0x%x sblock.fs_sparecon2\n", sblock.fs_sparecon2);
#ifdef _LITTLE_ENDIAN
printf("0x%x sblock.fs_npsect\n", sblock.fs_npsect);
#else
printf("0x%x sblock.fs_state\n", sblock.fs_state);
#endif
printf("0x%llx sblock.fs_qbmask\n", sblock.fs_qbmask);
printf("0x%llx sblock.fs_qfmask\n", sblock.fs_qfmask);
printf("0x%x sblock.fs_postblformat\n", sblock.fs_postblformat);
printf("0x%x sblock.fs_nrpos\n", sblock.fs_nrpos);
printf("0x%x sblock.fs_postbloff\n", sblock.fs_postbloff);
printf("0x%x sblock.fs_rotbloff\n", sblock.fs_rotbloff);
printf("0x%x sblock.fs_magic\n", sblock.fs_magic);
}
}