#ifdef linux
#define __APPLE__
#endif
#include "dkopen.h"
#include <sys/param.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <mach/boolean.h>
#include <sys/vm.h>
#ifdef linux
#include <fcntl.h>
#include <sys/statfs.h>
#include "ufslabel.h"
#if defined (linux) && defined (__powerpc__)
#define __ppc__
#endif
#include <sys/disklabel.h>
#define MAXPHYS (64 * 1024)
#define MAXPHYSIO MAXPHYS
#else
#include <sys/disklabel.h>
#include <sys/file.h>
#include <sys/mount.h>
#include <ufs/ufs/ufsmount.h>
#endif
#include <ufs/ufs/dir.h>
#include <ufs/ufs/dinode.h>
#include <ufs/ffs/fs.h>
#include <ctype.h>
#include <errno.h>
#include <paths.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <err.h>
#ifdef __APPLE__
int dkdisklabel __P((int fd, struct disklabel * lp));
int dkdisklabelregenerate __P((int fd, struct disklabel * lp, int newblksize));
#endif
#if __STDC__
#include <stdarg.h>
#else
#include <varargs.h>
#endif
#include "mntopts.h"
struct mntopt mopts[] = {
MOPT_STDOPTS,
MOPT_ASYNC,
{ NULL },
};
#ifdef __APPLE__
#include "ufslabel.h"
#endif __APPLE__
#if __STDC__
void fatal(const char *fmt, ...);
#else
void fatal();
#endif
#define COMPAT
#define DESFRAGSIZE 1024
#define DESBLKSIZE 8192
#define DESCPG 16
#ifdef __APPLE__
#define ROTDELAY 0
#else
#define ROTDELAY 4
#endif
#define MAXBLKPG(bsize) ((bsize) / sizeof(daddr_t))
#define NFPI 4
#define NRPOS 8
int Nflag;
int Oflag;
int fssize;
int ntracks;
int nsectors;
int nphyssectors;
int secpercyl;
int trackspares = -1;
int cylspares = -1;
int sectorsize;
int rpm;
int interleave;
int trackskew = -1;
int headswitch;
int trackseek;
int fsize = 0;
int bsize = 0;
#ifdef __APPLE__
int cpg = 0;
#else
int cpg = DESCPG;
#endif
int cpgflg;
int minfree = MINFREE;
int opt = DEFAULTOPT;
int density;
int maxcontig = 0;
int rotdelay = ROTDELAY;
int maxbpg;
int nrpos = NRPOS;
int avgfilesize = AVFILESIZ;
int avgfilesperdir = AFPDIR;
int bbsize = BBSIZE;
int sbsize = SBSIZE;
int mntflags = MNT_ASYNC;
u_long memleft;
caddr_t membase;
#ifdef COMPAT
char *disktype;
int unlabeled;
#endif
char device[MAXPATHLEN];
char *progname;
extern void mkfs(char *, int, int);
void usage();
int
main(argc, argv)
int argc;
char *argv[];
{
extern char *optarg;
extern int optind;
register int ch;
register struct partition *pp;
register struct disklabel *lp;
struct disklabel *getdisklabel();
struct partition oldpartition;
struct stat st;
struct statfs *mp;
int fsi, fso, len, n;
char *cp, *s1, *s2, *special, *opstring;
#ifdef __APPLE__
char * filesystem_name = "untitled";
#endif __APPLE__
if (progname = strrchr(*argv, '/'))
++progname;
else
progname = *argv;
opstring = "NOS:T:a:b:c:d:e:f:g:h:i:k:l:m:n:o:p:r:s:t:u:v:x:";
while ((ch = getopt(argc, argv, opstring)) != EOF)
switch (ch) {
case 'N':
Nflag = 1;
break;
case 'O':
Oflag = 1;
break;
case 'S':
if ((sectorsize = atoi(optarg)) <= 0)
fatal("%s: bad sector size", optarg);
break;
#ifdef COMPAT
case 'T':
disktype = optarg;
break;
#endif
case 'a':
if ((maxcontig = atoi(optarg)) <= 0)
fatal("%s: bad maximum contiguous blocks\n",
optarg);
break;
case 'b':
if ((bsize = atoi(optarg)) < MINBSIZE)
fatal("%s: bad block size", optarg);
break;
case 'c':
if ((cpg = atoi(optarg)) <= 0)
fatal("%s: bad cylinders/group", optarg);
cpgflg++;
break;
case 'd':
if ((rotdelay = atoi(optarg)) < 0)
fatal("%s: bad rotational delay\n", optarg);
break;
case 'e':
if ((maxbpg = atoi(optarg)) <= 0)
fatal("%s: bad blocks per file in a cylinder group\n",
optarg);
break;
case 'f':
if ((fsize = atoi(optarg)) <= 0)
fatal("%s: bad fragment size", optarg);
break;
case 'g':
if ((avgfilesize = atoi(optarg)) <= 0)
fatal("%s: bad average file size", optarg);
break;
case 'h':
if ((avgfilesperdir = atoi(optarg)) <= 0)
fatal("%s: bad average files per dir", optarg);
break;
case 'i':
if ((density = atoi(optarg)) <= 0)
fatal("%s: bad bytes per inode\n", optarg);
break;
case 'k':
if ((trackskew = atoi(optarg)) < 0)
fatal("%s: bad track skew", optarg);
break;
case 'l':
if ((interleave = atoi(optarg)) <= 0)
fatal("%s: bad interleave", optarg);
break;
case 'm':
if ((minfree = atoi(optarg)) < 0 || minfree > 99)
fatal("%s: bad free space %%\n", optarg);
break;
case 'n':
if ((nrpos = atoi(optarg)) <= 0)
fatal("%s: bad rotational layout count\n",
optarg);
break;
case 'o':
if (strcmp(optarg, "space") == 0)
opt = FS_OPTSPACE;
else if (strcmp(optarg, "time") == 0)
opt = FS_OPTTIME;
else
fatal("%s: unknown optimization preference: use `space' or `time'.");
break;
case 'p':
if ((trackspares = atoi(optarg)) < 0)
fatal("%s: bad spare sectors per track",
optarg);
break;
case 'r':
if ((rpm = atoi(optarg)) <= 0)
fatal("%s: bad revolutions/minute\n", optarg);
break;
case 's':
if ((fssize = atoi(optarg)) <= 0)
fatal("%s: bad file system size", optarg);
break;
case 't':
if ((ntracks = atoi(optarg)) <= 0)
fatal("%s: bad total tracks", optarg);
break;
case 'u':
if ((nsectors = atoi(optarg)) <= 0)
fatal("%s: bad sectors/track", optarg);
break;
#ifdef __APPLE__
case 'v':
filesystem_name = optarg;
break;
#endif __APPLE__
case 'x':
if ((cylspares = atoi(optarg)) < 0)
fatal("%s: bad spare sectors per cylinder",
optarg);
break;
case '?':
default:
usage();
}
argc -= optind;
argv += optind;
if (argc != 2 && (argc != 1))
usage();
special = argv[0];
cp = strrchr(special, '/');
#if defined (__APPLE__) && !defined (linux)
if (cp != 0)
special = cp + 1;
if (*special == 'r' && special[1] != 'a' && special[1] != 'b')
special++;
sprintf(device, "/dev/r%s", special);
#else
#if defined (linux)
if (cp != 0)
if (stat(special, &st) == -1)
fatal("%s: %s", special, strerror(errno));
else
sprintf(device, "%s", special);
#endif
if (cp == 0) {
(void)sprintf(device, "%sr%s", _PATH_DEV, special);
if (stat(device, &st) == -1)
(void)sprintf(device, "%s%s", _PATH_DEV, special);
special = device;
}
#endif
if (Nflag) {
fso = -1;
} else {
fso = dkopen(device, O_WRONLY, 0);
if (fso < 0)
fatal("%s: %s", special, strerror(errno));
#ifndef linux
n = getmntinfo(&mp, MNT_NOWAIT);
if (n == 0)
fatal("%s: getmntinfo: %s", special, strerror(errno));
len = sizeof(_PATH_DEV) - 1;
s1 = special;
if (strncmp(_PATH_DEV, s1, len) == 0)
s1 += len;
while (--n >= 0) {
s2 = mp->f_mntfromname;
if (strncmp(_PATH_DEV, s2, len) == 0) {
s2 += len - 1;
*s2 = 'r';
}
if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0)
fatal("%s is mounted on %s",
special, mp->f_mntonname);
++mp;
}
#endif
{
void * buf;
#define WIPE_START ((ssize_t)128 * 1024)
if (lseek(fso, 0, SEEK_SET) < 0) {
fatal("lseek failed on %s, %s",
special, strerror(errno));
}
buf = malloc(WIPE_START);
if (buf == NULL) {
fatal("malloc(WIPE_START) failed");
}
bzero(buf, WIPE_START);
if (write(fso, buf, WIPE_START) != WIPE_START) {
fatal("write(WIPE_START) %s failed, %s",
special, strerror(errno));
}
free(buf);
}
}
fsi = dkopen(device, O_RDONLY, 0);
if (fsi < 0)
fatal("%s: %s", special, strerror(errno));
if (fstat(fsi, &st) < 0)
fatal("%s: %s", special, strerror(errno));
if ((st.st_mode & S_IFMT) != S_IFCHR)
printf("%s: %s: not a character-special device\n",
progname, special);
#ifdef COMPAT
if (disktype == NULL)
disktype = argv[1];
#endif
lp = getdisklabel(special, fsi);
#ifdef __APPLE__
if (sectorsize) {
if (dkdisklabelregenerate(fsi, lp, sectorsize) < 0)
fatal("%s: invalid sector size", special);
}
#endif
pp = &lp->d_partitions[0];
if (pp->p_size == 0)
fatal("%s: partition is unavailable",
argv[0]);
if (pp->p_fstype == FS_BOOT)
fatal("%s: partition overlaps boot program",
argv[0]);
if (fssize == 0)
fssize = pp->p_size;
if (fssize > pp->p_size)
fatal("%s: maximum file system size on the partition is %d",
argv[0], pp->p_size);
if (rpm == 0) {
rpm = lp->d_rpm;
if (rpm <= 0)
rpm = 3600;
}
if (ntracks == 0) {
ntracks = lp->d_ntracks;
if (ntracks <= 0)
fatal("%s: no default #tracks", argv[0]);
}
if (nsectors == 0) {
nsectors = lp->d_nsectors;
if (nsectors <= 0)
fatal("%s: no default #sectors/track", argv[0]);
}
if (sectorsize == 0) {
sectorsize = lp->d_secsize;
if (sectorsize <= 0)
fatal("%s: no default sector size", argv[0]);
}
if (trackskew == -1) {
trackskew = lp->d_trackskew;
if (trackskew < 0)
trackskew = 0;
}
if (interleave == 0) {
interleave = lp->d_interleave;
if (interleave <= 0)
interleave = 1;
}
if (fsize == 0) {
fsize = pp->p_fsize;
if (fsize <= 0)
fsize = MAX(DESFRAGSIZE, lp->d_secsize);
}
if (bsize == 0) {
bsize = pp->p_frag * pp->p_fsize;
if (bsize <= 0)
bsize = MIN(DESBLKSIZE, 8 * fsize);
}
#ifdef __APPLE__
if (cpg == 0) {
cpg = pp->p_cpg;
if (cpg <= 0)
cpg = DESCPG;
}
#endif
if (maxcontig == 0)
maxcontig = MAX(1, MAXPHYS / bsize);
if (density == 0)
density = NFPI * fsize;
if (minfree < MINFREE && opt != FS_OPTSPACE) {
fprintf(stderr, "Warning: changing optimization to space ");
fprintf(stderr, "because minfree is less than %d%%\n", MINFREE);
opt = FS_OPTSPACE;
}
if (trackspares == -1) {
trackspares = lp->d_sparespertrack;
if (trackspares < 0)
trackspares = 0;
}
nphyssectors = nsectors + trackspares;
if (cylspares == -1) {
cylspares = lp->d_sparespercyl;
if (cylspares < 0)
cylspares = 0;
}
secpercyl = nsectors * ntracks - cylspares;
if (secpercyl != lp->d_secpercyl)
fprintf(stderr, "%s (%d) %s (%lu)\n",
"Warning: calculated sectors per cylinder", secpercyl,
"disagrees with disk label", lp->d_secpercyl);
if (maxbpg == 0)
maxbpg = MAXBLKPG(bsize);
headswitch = lp->d_headswitch;
trackseek = lp->d_trkseek;
bbsize = lp->d_bbsize;
sbsize = lp->d_sbsize;
oldpartition = *pp;
mkfs(special, fsi, fso);
if (!Nflag) {
close(fso);
#ifdef __APPLE__
fso = dkopen(device, O_RDWR, 0);
if (fso < 0) {
fatal("%s: couldn't label the filesystem on %s",
argv[0], special);
} else {
struct ufslabel ul;
ufslabel_init(&ul);
ufslabel_set_uuid(&ul);
if (ufslabel_set_name(&ul, filesystem_name,
strlen(filesystem_name)) == FALSE) {
fatal("%s: couldn't name the filesystem on %s",
argv[0], special);
}
if (ufslabel_set(fso, &ul) == FALSE) {
fatal("%s: couldn't label the filesystem on %s",
argv[0], special);
}
close(fso);
}
#endif __APPLE__
}
close(fsi);
exit(0);
}
#ifdef COMPAT
char lmsg[] = "%s: can't read disk label; disk type must be specified";
#else
char lmsg[] = "%s: can't read disk label";
#endif
struct disklabel *
getdisklabel(s, fd)
char *s;
int fd;
{
static struct disklabel lab;
#ifdef __APPLE__
if (dkdisklabel(fd, &lab) < 0)
#else
if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0)
#endif
{
warn("ioctl (GDINFO)");
fatal(lmsg, s);
}
return (&lab);
}
#ifndef __APPLE__
rewritelabel(s, fd, lp)
char *s;
int fd;
register struct disklabel *lp;
{
#ifdef COMPAT
if (unlabeled)
return;
#endif
lp->dl_checksum = 0;
lp->dl_checksum = dkcksum(lp);
if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0)
{
warn("ioctl (WDINFO)");
fatal("%s: can't rewrite disk label", s);
}
}
#endif
void
#if __STDC__
fatal(const char *fmt, ...)
#else
fatal(fmt, va_alist)
char *fmt;
va_dcl
#endif
{
va_list ap;
#if __STDC__
va_start(ap, fmt);
#else
va_start(ap);
#endif
if (fcntl(STDERR_FILENO, F_GETFL) < 0) {
openlog(progname, LOG_CONS, LOG_DAEMON);
vsyslog(LOG_ERR, fmt, ap);
closelog();
} else {
vwarnx(fmt, ap);
}
va_end(ap);
exit(1);
}
void
usage()
{
fprintf(stderr,
"usage: %s [ -fsoptions ] special-device%s\n",
progname,
#ifdef COMPAT
" [device-type]");
#else
"");
#endif
fprintf(stderr, "where fsoptions are:\n");
fprintf(stderr,
"\t-N do not create file system, just print out parameters\n");
fprintf(stderr, "\t-O create a 4.3BSD format filesystem\n");
fprintf(stderr, "\t-S sector size\n");
#ifdef COMPAT
fprintf(stderr, "\t-T disktype\n");
#endif
fprintf(stderr, "\t-a maximum contiguous blocks\n");
fprintf(stderr, "\t-b block size\n");
fprintf(stderr, "\t-c cylinders/group\n");
fprintf(stderr, "\t-d rotational delay between contiguous blocks\n");
fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n");
fprintf(stderr, "\t-f frag size\n");
fprintf(stderr, "\t-g average file size\n");
fprintf(stderr, "\t-h average files per directory\n");
fprintf(stderr, "\t-i number of bytes per inode\n");
fprintf(stderr, "\t-k sector 0 skew, per track\n");
fprintf(stderr, "\t-l hardware sector interleave\n");
fprintf(stderr, "\t-m minimum free space %%\n");
fprintf(stderr, "\t-n number of distinguished rotational positions\n");
fprintf(stderr, "\t-o optimization preference (`space' or `time')\n");
fprintf(stderr, "\t-p spare sectors per track\n");
fprintf(stderr, "\t-s file system size (sectors)\n");
fprintf(stderr, "\t-r revolutions/minute\n");
fprintf(stderr, "\t-t tracks/cylinder\n");
fprintf(stderr, "\t-u sectors/track\n");
fprintf(stderr, "\t-v filesystem/volume name\n");
fprintf(stderr, "\t-x spare sectors per cylinder\n");
exit(1);
}