1/*
2 * Copyright (c) 1999-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24
25#include <err.h>
26#include <errno.h>
27#include <fcntl.h>
28#include <grp.h>
29#include <paths.h>
30#include <pwd.h>
31#include <stdlib.h>
32#include <stdio.h>
33#include <string.h>
34#include <ctype.h>
35#include <syslog.h>
36#include <unistd.h>
37
38#include <sys/ioctl.h>
39#include <sys/mount.h>
40#include <sys/param.h>
41#include <sys/stat.h>
42
43#include <IOKit/storage/IOMediaBSDClient.h>
44
45#include <hfs/hfs_format.h>
46#include "newfs_hfs.h"
47
48#if __STDC__
49#include <stdarg.h>
50#else
51#include <varargs.h>
52#endif
53
54#define	NOVAL       (-1)
55#define UMASK       (0755)
56#define	ACCESSMASK  (0777)
57
58/*
59 * The maximum HFS volume size is calculated thusly:
60 *
61 * The maximum allocation block size (which must be a power of 2 value),
62 * is 2GB, or 2^31 bytes
63 *
64 * The maximum number of allocation blocks is 2^32 -1.
65 *
66 * Multiplying that out yields 2GB * ( 4GB - 1 ) == 2GB*4GB  - 2GB.
67 * More explicitly, 8 exabytes - 2 gigabytes,
68 * or 0x7FFFFFFF80000000 bytes.  That gives us our value below.
69 */
70
71#define MAXHFSVOLSIZE (0x7FFFFFFF80000000ULL)
72
73#define ROUNDUP(x,y) (((x)+(y)-1)/(y)*(y))
74
75static void getnodeopts __P((char* optlist));
76static void getclumpopts __P((char* optlist));
77#ifdef DEBUG_BUILD
78static void getstartopts __P((char *optlist));
79static void getextsopts __P((char* optlist));
80#endif
81static gid_t a_gid __P((char *));
82static uid_t a_uid __P((char *));
83static mode_t a_mask __P((char *));
84static int hfs_newfs __P((char *device));
85static void validate_hfsplus_block_size __P((UInt64 sectorCount, UInt32 sectorSize));
86static void hfsplus_params __P((const DriveInfo* dip, hfsparams_t *defaults));
87static UInt32 clumpsizecalc __P((UInt32 clumpblocks));
88static UInt32 CalcHFSPlusBTreeClumpSize __P((UInt32 blockSize, UInt32 nodeSize, UInt64 sectors, int fileID));
89static void usage __P((void));
90static int get_high_bit (u_int64_t bitstring);
91static int bad_disk_size (u_int64_t numsectors, u_int64_t sectorsize);
92
93
94
95char	*progname;
96char	*gVolumeName = kDefaultVolumeNameStr;
97char	rawdevice[MAXPATHLEN];
98char	blkdevice[MAXPATHLEN];
99uint32_t gBlockSize = 0;
100UInt32	gNextCNID = kHFSFirstUserCatalogNodeID;
101
102time_t  createtime;
103
104int	gNoCreate = FALSE;
105int	gUserCatNodeSize = FALSE;
106int	gCaseSensitive = FALSE;
107int	gUserAttrSize = FALSE;
108int gContentProtect = FALSE;
109
110static UInt32	attrExtCount = 1, blkallocExtCount = 1, catExtCount = 1, extExtCount = 1;
111static UInt32	attrExtStart = 0, blkallocExtStart = 0, catExtStart = 0, extExtStart = 0;
112static UInt32	jibStart = 0, jnlStart = 0, allocStart = 0;
113
114#ifdef DEBUG_BUILD
115uint16_t gProtectLevel = 0;
116#endif
117
118#define JOURNAL_DEFAULT_SIZE (8*1024*1024)
119int     gJournaled = FALSE;
120char    *gJournalDevice = NULL;
121UInt64	gJournalSize = 0;
122
123uid_t	gUserID = (uid_t)NOVAL;
124gid_t	gGroupID = (gid_t)NOVAL;
125mode_t	gModeMask = (mode_t)NOVAL;
126
127/* Starting allocation block number for the file system,
128 * all btrees, including journal will be laid down at this
129 * alloation block offset.
130 */
131UInt32	gFSStartBlock = 0;
132
133UInt64	gPartitionSize = 0;
134
135UInt32	catnodesiz = 8192;
136UInt32	extnodesiz = 4096;
137UInt32	atrnodesiz = 8192;
138
139UInt32	catclumpblks = 0;
140UInt32	extclumpblks = 0;
141UInt32	atrclumpblks = 0;
142UInt32	bmclumpblks = 0;
143UInt32	rsrclumpblks = 0;
144UInt32	datclumpblks = 0;
145uint32_t hfsgrowblks = 0;      /* maximum growable size of wrapper */
146
147
148UInt64
149get_num(char *str)
150{
151    UInt64 num;
152    char *ptr;
153
154    num = strtoull(str, &ptr, 0);
155
156    if (*ptr) {
157	    char scale = tolower(*ptr);
158
159	    switch(scale) {
160	    case 'b':
161		    num *= 512ULL;
162		    break;
163	    case 'p':
164		    num *= 1024ULL;
165		    /* fall through */
166	    case 't':
167		    num *= 1024ULL;
168		    /* fall through */
169	    case 'g':
170		    num *= 1024ULL;
171		    /* fall through */
172	    case 'm':
173		    num *= 1024ULL;
174		    /* fall through */
175	    case 'k':
176		    num *= 1024ULL;
177		    break;
178
179	    default:
180		    num = 0ULL;
181		    break;
182	}
183    }
184    return num;
185}
186
187
188int
189main(argc, argv)
190	int argc;
191	char **argv;
192{
193	extern char *optarg;
194	extern int optind;
195	int ch;
196	char *cp, *special;
197	struct statfs *mp;
198	int n;
199
200	if ((progname = strrchr(*argv, '/')))
201		++progname;
202	else
203		progname = *argv;
204
205// No semicolon at end of line deliberately!
206
207	static const char *options = "G:J:D:M:N:PU:hsb:c:i:n:v:"
208#ifdef DEBUG_BUILD
209		"p:a:E:"
210#endif
211		;
212
213	while ((ch = getopt(argc, argv, options)) != -1)
214		switch (ch) {
215		case 'G':
216			gGroupID = a_gid(optarg);
217			break;
218
219		case 'J':
220			gJournaled = TRUE;
221			if (isdigit(optarg[0])) {
222			    gJournalSize = get_num(optarg);
223			    if (gJournalSize < 512*1024) {
224					printf("%s: journal size %lldk too small.  Reset to %dk.\n",
225						progname, gJournalSize/1024, JOURNAL_DEFAULT_SIZE/1024);
226					gJournalSize = JOURNAL_DEFAULT_SIZE;
227			    }
228			} else {
229				/* back up because there was no size argument */
230			    optind--;
231			}
232			break;
233
234		case 'D':
235			gJournalDevice = (char *)optarg;
236			break;
237
238		case 'N':
239			gNoCreate = TRUE;
240			if (isdigit(optarg[0])) {
241				gPartitionSize = get_num(optarg);
242			} else {
243				/* back up because there was no size argument */
244				optind--;
245			}
246			break;
247
248		case 'P':
249			gContentProtect = TRUE;
250			break;
251
252#ifdef DEBUG_BUILD
253		case 'p':
254			if (isdigit (optarg[0])) {
255				uint64_t level = get_num (optarg);
256				gProtectLevel  = (uint16_t) level;
257			}
258			else {
259				/* back up because no level was provided */
260				optind--;
261			}
262			break;
263#endif
264
265		case 'M':
266			gModeMask = a_mask(optarg);
267			break;
268
269		case 'U':
270			gUserID = a_uid(optarg);
271			break;
272
273#ifdef DEBUG_BUILD
274		case 'a':
275			getstartopts(optarg);
276			break;
277#endif
278
279#ifdef DEBUG_BUILD
280		case 'E':
281			getextsopts(optarg);
282			break;
283#endif
284		case 'b':
285		{
286			UInt64 tempBlockSize;
287
288			tempBlockSize = get_num(optarg);
289			if (tempBlockSize < HFSMINBSIZE)
290				fatal("%s: bad allocation block size (too small)", optarg);
291			if (tempBlockSize > HFSMAXBSIZE)
292				fatal("%s: bad allocation block size (too large)", optarg);
293			gBlockSize = tempBlockSize;
294			break;
295		}
296
297		case 'c':
298			getclumpopts(optarg);
299			break;
300
301		case 'i':
302			gNextCNID = atoi(optarg);
303			/*
304			 * make sure its at least kHFSFirstUserCatalogNodeID
305			 */
306			if (gNextCNID < kHFSFirstUserCatalogNodeID)
307				fatal("%s: starting catalog node id too small (must be > 15)", optarg);
308			break;
309
310		case 'n':
311			getnodeopts(optarg);
312			break;
313
314		case 's':
315			gCaseSensitive = TRUE;
316			break;
317
318		case 'v':
319			if ((gVolumeName = strdup(optarg)) == NULL) {
320				fatal("Could not copy volume name %s", optarg);
321			}
322			break;
323
324		case '?':
325		default:
326			usage();
327		}
328
329	argc -= optind;
330	argv += optind;
331
332#ifdef DEBUG_BUILD
333	if ((gProtectLevel) && !(gContentProtect)) {
334		fatal ("content protection must be specified to set a protection level");
335	}
336#endif
337
338	if (gPartitionSize != 0) {
339		/*
340		 * If we are given -N, a size, and a device, that's a usage error.
341		 */
342		if (argc != 0)
343			usage();
344
345		rawdevice[0] = blkdevice[0] = 0;
346	} else {
347		if (argc != 1)
348			usage();
349
350		special = argv[0];
351		cp = strrchr(special, '/');
352		if (cp != 0)
353			special = cp + 1;
354		if (*special == 'r')
355			special++;
356		(void) snprintf(rawdevice, sizeof(rawdevice), "%sr%s", _PATH_DEV, special);
357		(void) snprintf(blkdevice, sizeof(blkdevice), "%s%s", _PATH_DEV, special);
358	}
359
360	if (gPartitionSize == 0) {
361		/*
362		 * Check if target device is aready mounted
363		 */
364		n = getmntinfo(&mp, MNT_NOWAIT);
365		if (n == 0)
366			fatal("%s: getmntinfo: %s", blkdevice, strerror(errno));
367
368		while (--n >= 0) {
369			if (strcmp(blkdevice, mp->f_mntfromname) == 0)
370				fatal("%s is mounted on %s", blkdevice, mp->f_mntonname);
371			++mp;
372		}
373	}
374
375	if (hfs_newfs(rawdevice) < 0) {
376		err(1, "cannot create filesystem on %s", rawdevice);
377	}
378
379	exit(0);
380}
381
382
383static void getnodeopts(char* optlist)
384{
385	char *strp = optlist;
386	char *ndarg;
387	char *p;
388	UInt32 ndsize;
389
390	while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
391
392		p = strchr(ndarg, '=');
393		if (p == NULL)
394			usage();
395
396		ndsize = atoi(p+1);
397
398		switch (*ndarg) {
399		case 'c':
400			if (ndsize < 4096 || ndsize > 32768 || (ndsize & (ndsize-1)) != 0)
401				fatal("%s: invalid catalog b-tree node size", ndarg);
402			catnodesiz = ndsize;
403			gUserCatNodeSize = TRUE;
404			break;
405
406		case 'e':
407			if (ndsize < 1024 || ndsize > 32768 || (ndsize & (ndsize-1)) != 0)
408				fatal("%s: invalid extents b-tree node size", ndarg);
409			extnodesiz = ndsize;
410			break;
411
412		case 'a':
413			if (ndsize < 4096 || ndsize > 32768 || (ndsize & (ndsize-1)) != 0)
414				fatal("%s: invalid atrribute b-tree node size", ndarg);
415			atrnodesiz = ndsize;
416			break;
417
418		default:
419			usage();
420		}
421	}
422}
423
424
425static void getclumpopts(char* optlist)
426{
427	char *strp = optlist;
428	char *ndarg;
429	char *p;
430	UInt32 clpblocks;
431
432	while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
433
434		p = strchr(ndarg, '=');
435		if (p == NULL)
436			usage();
437
438		clpblocks = atoi(p+1);
439
440		switch (*ndarg) {
441		case 'a':
442			atrclumpblks = clpblocks;
443			gUserAttrSize = TRUE;
444			break;
445		case 'b':
446			bmclumpblks = clpblocks;
447			break;
448		case 'c':
449			catclumpblks = clpblocks;
450			break;
451		case 'd':
452			datclumpblks = clpblocks;
453			break;
454		case 'e':
455			extclumpblks = clpblocks;
456			break;
457		case 'r':
458			rsrclumpblks = clpblocks;
459			break;
460
461		default:
462			usage();
463		}
464	}
465}
466
467#ifdef DEBUG_BUILD
468static void getextsopts(char* optlist)
469{
470	char *strp = optlist;
471	char *ndarg;
472	char *p;
473	UInt32 numexts;
474
475	while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
476
477		p = strchr(ndarg, '=');
478		if (p == NULL)
479			usage();
480
481		numexts = atoi(p+1);
482
483		switch (*ndarg) {
484		case 'a':
485			attrExtCount = numexts;
486			break;
487		case 'b':
488			blkallocExtCount = numexts;
489			break;
490		case 'c':
491			catExtCount = numexts;
492			break;
493		case 'e':
494			extExtCount = numexts;
495			break;
496		default:
497			usage();
498		}
499	}
500}
501
502static void getstartopts(char* optlist)
503{
504	char *strp;
505	char *ndarg;
506	char *p;
507	unsigned long startat = 0;
508
509	startat = strtoul(optlist, &strp, 0);
510	if (startat == ULONG_MAX && errno != 0) {
511		err(1, "invalid allocation start block string %s", optlist);
512	}
513	if (startat > UINT_MAX) {
514		errx(1, "Allocation block %lu larger than max", startat);
515	}
516	if (strp && *strp == ',')
517		strp++;
518
519	gFSStartBlock = startat;
520
521	while((ndarg = strsep(&strp, ",")) != NULL && *ndarg != '\0') {
522
523		startat = strtoul(optlist, NULL, 0);
524		p = strchr(ndarg, '=');
525		if (p == NULL)
526			usage();
527
528		startat = atoi(p+1);
529
530		switch (*ndarg) {
531		case 'a':
532			attrExtStart = startat;
533			break;
534		case 'b':
535			blkallocExtStart = startat;
536			break;
537		case 'c':
538			catExtStart = startat;
539			break;
540		case 'e':
541			extExtStart = startat;
542			break;
543		case 'j':
544			jibStart = startat;
545			break;
546		case 'J':
547			jnlStart = startat;
548			break;
549		case 'N':
550			allocStart = startat;
551			break;
552		default:
553			usage();
554		}
555	}
556}
557#endif
558
559gid_t
560static a_gid(char *s)
561{
562	struct group *gr;
563	char *gname;
564	gid_t gid = 0;
565
566	if ((gr = getgrnam(s)) != NULL)
567		gid = gr->gr_gid;
568	else {
569		for (gname = s; *s && isdigit(*s); ++s);
570		if (!*s)
571			gid = atoi(gname);
572		else
573			errx(1, "unknown group id: %s", gname);
574	}
575	return (gid);
576}
577
578static uid_t
579a_uid(char *s)
580{
581	struct passwd *pw;
582	char *uname;
583	uid_t uid = 0;
584
585	if ((pw = getpwnam(s)) != NULL)
586		uid = pw->pw_uid;
587	else {
588		for (uname = s; *s && isdigit(*s); ++s);
589		if (!*s)
590			uid = atoi(uname);
591		else
592			errx(1, "unknown user id: %s", uname);
593	}
594	return (uid);
595}
596
597static mode_t
598a_mask(char *s)
599{
600	int done, rv;
601	char *ep;
602
603	done = 0;
604	rv = -1;
605	if (*s >= '0' && *s <= '7') {
606		done = 1;
607		rv = strtol(s, &ep, 8);
608	}
609	if (!done || rv < 0 || *ep)
610		errx(1, "invalid access mask: %s", s);
611	return (rv);
612}
613
614/*
615 * Check to see if the volume is too big.
616 *
617 * Returns:
618 *		0 if it is appropriately sized.
619 *		1 if HFS+ cannot be formatted onto the disk.
620 */
621
622static int bad_disk_size (u_int64_t numsectors, u_int64_t sectorsize) {
623
624	u_int32_t maxSectorBits = 0;
625	u_int32_t maxSectorSizeBits = 0;
626	u_int32_t maxBits = 0;
627	u_int64_t bytes;
628
629	/*
630	 * The essential problem here is that we cannot simply multiply the sector size by the
631	 * number of sectors because the product could overflow a 64 bit integer.  We do a cursory
632	 * check and then a longer check once we know the product will not overflow.
633	 */
634
635	maxSectorBits = get_high_bit (numsectors);
636	maxSectorSizeBits = get_high_bit (sectorsize);
637
638	/*
639	 * We get the number of bits to represent the number of sectors and the sector size.
640	 * Adding the two numbers gives us the number of bits required to represent the product.
641	 * If the product is > 63 then it must be too big.
642	 */
643
644	maxBits = maxSectorBits + maxSectorSizeBits;
645	if (maxBits > 63) {
646		return 1;
647	}
648
649	/* Well, now we know that the two values won't overflow.  Time to multiply */
650	bytes = numsectors * sectorsize;
651
652	if (bytes > MAXHFSVOLSIZE) {
653		/* Too big! */
654		return 1;
655	}
656
657	/* Otherwise, it looks good */
658	return 0;
659
660}
661
662/*
663 * The allocation block size must be defined as a power of 2 value, with a floor of
664 * 512 bytes.  However, we never default to anything less than 4096 bytes, so that
665 * gives us 20 block size values from 4kb -> 2GB block size.
666 *
667 * See inline comments for how this table is used to determine the minimum fs size that
668 * will use a specified allocation block size.
669 *
670 * The growth boundary is used to figure out if we need a bigger block size than the
671 * 4 KB default.  We get the index of the highest bit set in the FS size, then subtract the
672 * growth boundary to index into the block allocation size array.
673 *
674 * Note that 8K appears twice in table since we want to use it for the range 2 TB < 8 TB FS size.
675 * This means that when the 2TB bit or the 4TB bit is the high bit set, we prefer the 8K block size.
676 */
677#define NUM_ALLOC_BLOCKSIZES 21
678#define GROWTH_BOUNDARY 41
679
680u_int64_t alloc_blocksize[NUM_ALLOC_BLOCKSIZES] =  {
681	/* Block Size*/ /* Min Dflt FS Size */ /* Max FS Size */
682	4096,			/* 0 bytes */			/* 16 TB */
683	8192,			/* 2 TB */				/* 32 TB */		/* Note that 8K appears twice in table ! */
684	8192,			/* 4 TB */				/* 32 TB */		/* Note that 8K appears twice in table ! */
685	16384,			/* 8 TB */				/* 64 TB */
686	32768,			/* 16 TB */				/* 128 TB */
687	65536,			/* 32 TB */				/* 256 TB */
688	131072,			/* 64 TB */				/* 512 TB */
689	262144,			/* 128 TB */			/* 1 PB */
690	524288,			/* 256 TB */			/* 2 PB */
691	1048576,		/* 512 TB */			/* 4 PB */
692	2097152,		/* 1 PB */				/* 8 PB */
693	4194304,		/* 2 PB */				/* 16 PB */
694	8388608,		/* 4 PB */				/* 32 PB */
695	16777216,		/* 8 PB */				/* 64 PB */
696	33554432,		/* 16 PB */				/* 128 PB */
697	67108864,		/* 32 PB */				/* 256 PB */
698	134217728,		/* 64 PB */				/* 512 PB */
699	268435456,		/* 128 PB */			/* 1 EB */
700	536870912,		/* 256 PB */			/* 2 EB */
701	1073741824,		/* 512 PB */			/* 4 EB */
702	2147483648ULL	/* 1 EB */				/* 8 EB */
703};
704
705static int get_high_bit (u_int64_t bitstring) {
706	u_int64_t bits = bitstring;
707	int counter = 0;
708	while (bits) {
709		bits = (bits >> 1);
710		counter++;
711	}
712	return counter;
713}
714
715
716/*
717 * Validate the HFS Plus allocation block size in gBlockSize.  If none was
718 * specified, then calculate a suitable default.
719 *
720 * Modifies the global variable gBlockSize.
721 */
722static void validate_hfsplus_block_size(UInt64 sectorCount, UInt32 sectorSize)
723{
724	if (gBlockSize == 0) {
725
726		/* Start by calculating the fs size */
727		u_int64_t fs_size = sectorCount * sectorSize;
728
729		/*
730		 * Determine the default based on a sliding scale.  The maximum number of
731		 * allocation blocks is always 4294967295 == (32 bits worth).  At 1 bit per
732		 * allocation block, that yields 512 MB of bitmap no matter what size we use
733		 * for the allocation block.
734		 *
735		 * The general default policy is to allow the filesystem to grow up to 8x the
736		 * current maximum size.  So for a 1.5TB filesystem, an 8x multiplier would be
737		 * 12TB.  That means we can use the default size of 4096 bytes.  The boundary begins
738		 * at 2TB, since at that point, we can no longer use the default 4096 block size to
739		 * extend the filesystem by 8x.  For a 16KB block size, the max is 64 TB, but the 8x
740		 * multiplier begins at 8 TB.  Thereafter, we increase for every power of 2 that
741		 * the current filesystem size grows.
742		 */
743
744		gBlockSize = DFL_BLKSIZE;	/* Prefer the default of 4K */
745
746		int bit_index = get_high_bit (fs_size);
747		bit_index -= GROWTH_BOUNDARY;
748
749		/*
750		 * After subtracting the GROWTH_BOUNDARY to index into the array, we'll
751		 * use the values in the static array if we have a non-negative index.
752		 * That means that if the filesystem is >= 1 TB, then we'll use the index
753		 * value. At 2TB, we grow to the 8K block size.
754		 */
755		if ((bit_index >= 0) && (bit_index < 22)) {
756			gBlockSize = alloc_blocksize[bit_index];
757		}
758
759		if (bit_index >= 22) {
760			fatal("Error: Disk Device is too big (%llu sectors, %d bytes per sector", sectorCount, sectorSize);
761		}
762	}
763	else {
764		/* Make sure a user-specified block size is reasonable */
765		if ((gBlockSize & (gBlockSize-1)) != 0) {
766			fatal("%s: bad HFS Plus allocation block size (must be a power of two)", optarg);
767		}
768
769		if ((sectorCount / (gBlockSize / sectorSize)) > 0xFFFFFFFF) {
770			fatal("%s: block size is too small for %lld sectors", optarg, gBlockSize, sectorCount);
771		}
772
773		if (gBlockSize < HFSOPTIMALBLKSIZE) {
774			warnx("Warning: %u is a non-optimal block size (4096 would be a better choice)", (unsigned int)gBlockSize);
775		}
776	}
777
778	if (gFSStartBlock) {
779		u_int64_t fs_size = sectorCount * sectorSize;
780		u_int32_t totalBlocks = fs_size/gBlockSize;
781
782		if (gFSStartBlock >= totalBlocks) {
783			warnx("Warning: %u is invalid file system start allocation block number, must be less than total allocation blocks (%u)", (unsigned int)gFSStartBlock, (unsigned int)totalBlocks);
784			warnx("Warning: Resetting file system start block to zero");
785			gFSStartBlock = 0;
786		}
787	}
788}
789
790
791
792static int
793hfs_newfs(char *device)
794{
795	struct stat stbuf;
796	DriveInfo dip = { 0 };
797	int fso = -1;
798	int retval = 0;
799	hfsparams_t defaults = {0};
800	UInt64 maxPhysPerIO = 0;
801
802	if (gPartitionSize) {
803		dip.sectorSize = kBytesPerSector;
804		dip.physTotalSectors = dip.totalSectors = gPartitionSize / kBytesPerSector;
805		dip.physSectorSize = kBytesPerSector;	/* 512-byte sectors */
806		dip.fd = 0;
807	} else {
808		if (gNoCreate) {
809			fso = open( device, O_RDONLY | O_NDELAY, 0 );
810		} else {
811			fso = open( device, O_RDWR | O_NDELAY, 0 );
812		}
813		if (fso == -1) {
814			return -1;
815		}
816
817		dip.fd = fso;
818		fcntl(fso, F_NOCACHE, 1);
819
820		if (fso < 0)
821			fatal("%s: %s", device, strerror(errno));
822
823		if (fstat( fso, &stbuf) < 0)
824			fatal("%s: %s", device, strerror(errno));
825
826		if (ioctl(fso, DKIOCGETBLOCKSIZE, &dip.physSectorSize) < 0)
827			fatal("%s: %s", device, strerror(errno));
828
829		if ((dip.physSectorSize % kBytesPerSector) != 0)
830			fatal("%d is an unsupported sector size\n", dip.physSectorSize);
831
832		if (ioctl(fso, DKIOCGETBLOCKCOUNT, &dip.physTotalSectors) < 0)
833			fatal("%s: %s", device, strerror(errno));
834
835	}
836
837	dip.physSectorsPerIO = (1024 * 1024) / dip.physSectorSize;  /* use 1M as default */
838
839	if (fso != -1 && ioctl(fso, DKIOCGETMAXBLOCKCOUNTREAD, &maxPhysPerIO) < 0)
840		fatal("%s: %s", device, strerror(errno));
841
842	if (maxPhysPerIO)
843		dip.physSectorsPerIO = MIN(dip.physSectorsPerIO, maxPhysPerIO);
844
845	if (fso != -1 && ioctl(fso, DKIOCGETMAXBLOCKCOUNTWRITE, &maxPhysPerIO) < 0)
846		fatal("%s: %s", device, strerror(errno));
847
848	if (maxPhysPerIO)
849		dip.physSectorsPerIO = MIN(dip.physSectorsPerIO, maxPhysPerIO);
850
851	if (fso != -1 && ioctl(fso, DKIOCGETMAXBYTECOUNTREAD, &maxPhysPerIO) < 0)
852		fatal("%s: %s", device, strerror(errno));
853
854	if (maxPhysPerIO)
855		dip.physSectorsPerIO = MIN(dip.physSectorsPerIO, maxPhysPerIO / dip.physSectorSize);
856
857	if (fso != -1 && ioctl(fso, DKIOCGETMAXBYTECOUNTWRITE, &maxPhysPerIO) < 0)
858		fatal("%s: %s", device, strerror(errno));
859
860	if (maxPhysPerIO)
861		dip.physSectorsPerIO = MIN(dip.physSectorsPerIO, maxPhysPerIO / dip.physSectorSize);
862
863	dip.sectorSize = kBytesPerSector;
864	dip.totalSectors = dip.physTotalSectors * dip.physSectorSize / dip.sectorSize;
865
866	dip.sectorOffset = 0;
867	time(&createtime);
868
869	/* Check to see if the disk is too big */
870	u_int64_t secsize = (u_int64_t) dip.sectorSize;
871	if (bad_disk_size(dip.totalSectors, secsize)) {
872		fatal("%s: partition is too big (maximum is %llu KB)", device, MAXHFSVOLSIZE/1024);
873	}
874
875	/*
876	 * If we're going to make an HFS Plus disk (with or without a wrapper), validate the
877	 * HFS Plus allocation block size.  This will also calculate a default allocation
878	 * block size if none (or zero) was specified.
879	 */
880	validate_hfsplus_block_size(dip.totalSectors, dip.sectorSize);
881
882	/* Make an HFS Plus disk */
883
884	if ((dip.totalSectors * dip.sectorSize ) < kMinHFSPlusVolumeSize)
885		fatal("%s: partition is too small (minimum is %d KB)", device, kMinHFSPlusVolumeSize/1024);
886
887	hfsplus_params(&dip, &defaults);
888	if (gNoCreate == 0) {
889		retval = make_hfsplus(&dip, &defaults);
890		if (retval == 0) {
891			printf("Initialized %s as a ", device);
892			if (dip.totalSectors > 2048ULL*1024*1024)
893				printf("%ld TB",
894						(long)((dip.totalSectors + (1024ULL*1024*1024))/(2048ULL*1024*1024)));
895			else if (dip.totalSectors > 2048*1024)
896				printf("%ld GB",
897						(long)((dip.totalSectors + (1024*1024))/(2048*1024)));
898			else if (dip.totalSectors > 2048)
899				printf("%ld MB",
900						(long)((dip.totalSectors + 1024)/2048));
901			else
902				printf("%ld KB",
903						(long)((dip.totalSectors + 1)/2));
904
905			if (gCaseSensitive) {
906				printf(" case-sensitive");
907			}
908			else {
909				printf(" case-insensitive");
910			}
911			if (gJournaled)
912				printf(" HFS Plus volume with a %uk journal\n",
913						(u_int32_t)defaults.journalSize/1024);
914			else
915				printf(" HFS Plus volume\n");
916		}
917	}
918
919	if (retval)
920		fatal("%s: %s", device, strerror(errno));
921
922	if ( fso > 0 ) {
923		close(fso);
924	}
925
926	return retval;
927}
928
929/*
930 typedef struct block_info {
931	off_t       bnum;		//64 bit
932	union {
933		_blk_info   bi;		//64 bit
934		struct buf *bp;		//64 bit on K64, 32 bit on K32
935	} u;
936 }__attribute__((__packed__)) block_info;
937
938 total size == 16 bytes
939 */
940
941#define BLOCK_INFO_SIZE 16
942
943static void hfsplus_params (const DriveInfo* dip, hfsparams_t *defaults)
944{
945	UInt64  sectorCount = dip->totalSectors;
946	UInt32  sectorSize = dip->sectorSize;
947	uint32_t totalBlocks;
948	UInt32	minClumpSize;
949	UInt32	clumpSize;
950	UInt32	oddBitmapBytes;
951
952	defaults->flags = 0;
953	defaults->blockSize = gBlockSize;
954	defaults->fsStartBlock = gFSStartBlock;
955	defaults->nextFreeFileID = gNextCNID;
956	defaults->createDate = createtime + MAC_GMT_FACTOR;     /* Mac OS GMT time */
957	defaults->hfsAlignment = 0;
958	defaults->journaledHFS = gJournaled;
959	defaults->journalDevice = gJournalDevice;
960
961	/*
962	 * 8429818
963	 * Always set kUseAccessPerms now; this also
964	 * means we have to always have an owner, group,
965	 * and mask.
966	 */
967	defaults->owner = (gUserID == (uid_t)NOVAL) ? geteuid() : gUserID;
968	defaults->group = (gGroupID == (gid_t)NOVAL) ? getegid() : gGroupID;
969	defaults->mask = (gModeMask == (mode_t)NOVAL) ? UMASK : (gModeMask & ACCESSMASK);
970	defaults->flags |= kUseAccessPerms;
971
972	/*
973	 * We want at least 8 megs of journal for each 100 gigs of
974	 * disk space.  We cap the size at 512 megs (64x default), unless
975	 * the allocation block size is larger, in which case we use one
976	 * allocation block.
977	 *
978	 * Only scale if it's the default, otherwise just take what
979	 * the user specified, with the caveat below.
980	 */
981	if (gJournaled) {
982		uint32_t min_size = 0;
983
984		/*
985		 * Check to ensure the journal size is not too small relative to the
986		 * sector size of the device.  This is the check in the kernel:
987		 if (tr->blhdr && (tr->blhdr->max_blocks <= 0 ||
988		 tr->blhdr->max_blocks > (tr->jnl->jhdr->size/tr->jnl->jhdr->jhdr_size)))
989		 * We assume that there will be a block header and that there will be a
990		 * non-negative max_blocks value.
991		 *
992		 * The 2nd check is the problematic one.  We cannot have a journal that's too
993		 * small relative to the sector size.  max_blocks == (blhdr_size / 16).  However,
994		 * this only matters where the current block header size is smaller than the current
995		 * sector size. So, assume that the blhdr_size == sector size for now.  We look
996		 * at the condition above to get the rest of the equation -- (journal size / sector size).
997		 * Then, it's simple algebra to figure out what the new minimum journal size
998		 * should be:
999		 *
1000		 *	(sector_size / 16) > (journal_size / sector_size)
1001		 *	(sector_size / 16) = (journal_size / sector_size)
1002		 *	(sector_size / 16) * sector_size = (journal_size / sector_size) * sector_size
1003		 *	(sector_size / 16) * sector_size = journal_size
1004		 *
1005		 *  This becomes our new _floor_ for the journal_size.
1006		 */
1007
1008		if (dip->physSectorSize != 0) {
1009			min_size = dip->physSectorSize * (dip->physSectorSize / BLOCK_INFO_SIZE);
1010		}
1011
1012		if (gJournalSize != 0) {
1013
1014			/* Was the supplied journal size at least the minimum computed above? */
1015			if (gJournalSize < min_size) {
1016				printf("%s: journal size %lldk too small.  Reset to %dk.\n",
1017						progname, gJournalSize/1024, JOURNAL_DEFAULT_SIZE/1024);
1018				gJournalSize = 0;
1019
1020			}
1021			/* defaults->journalSize will get reset below if it is 0 */
1022			defaults->journalSize = gJournalSize;
1023		}
1024
1025		if ((gJournalSize == 0) || (defaults->journalSize == 0)) {
1026			UInt32 jscale;
1027			uint32_t target_size;
1028			/* Figure out how many 100's of GBs this filesystem represents */
1029			jscale = (sectorCount * sectorSize) / ((UInt64)100 * 1024 * 1024 * 1024);
1030			if (jscale > 64) {
1031				jscale = 64;
1032			}
1033
1034			target_size = JOURNAL_DEFAULT_SIZE * (jscale + 1);
1035			/* Is the target size at least the min_size computed above? */
1036			if (target_size < min_size) {
1037				target_size = min_size;
1038			}
1039
1040			defaults->journalSize = target_size;
1041		}
1042
1043
1044#ifndef DEBUG_BUILD
1045		// volumes that are 128 megs or less in size have such
1046		// a small bitmap (one 4k-block) and inherhently such
1047		// a small btree that we can get by with a much smaller
1048		// journal.  even in a worst case scenario of a catalog
1049		// filled with very long korean file names we should
1050		// never touch more than 256k of meta-data for a single
1051		// transaction.  therefore we'll make the journal 512k,
1052		// or as small as possible, given the sector size,
1053		// which is safe and doesn't waste much space.
1054		// However, be careful not to let the journal size drop BELOW
1055		// 512k, since the min_size computations can create an artificially
1056		// tiny journal (16k or so) with 512byte sectors.
1057		//
1058		if (sectorCount * sectorSize < 128*1024*1024) {
1059			/* This is a small (<128MB) FS */
1060			uint32_t small_default = (512 * 1024);
1061
1062			if (small_default <= min_size) {
1063				/*
1064				 * If 512k is too small given the sector size,
1065				 * then use the larger sector size
1066				 */
1067				defaults->journalSize = min_size;
1068			}
1069			else {
1070				/* 512k was bigger than the min size; we can use it */
1071				defaults->journalSize = small_default;
1072			}
1073		}
1074#endif
1075
1076		if (defaults->journalSize > 512 * 1024 * 1024) {
1077			defaults->journalSize = 512 * 1024 * 1024;
1078		}
1079
1080		if (defaults->journalSize < defaults->blockSize) {
1081			defaults->journalSize = defaults->blockSize;
1082		}
1083	}
1084
1085	defaults->volumeName = (unsigned char*)gVolumeName;
1086
1087	if (rsrclumpblks == 0) {
1088		if (gBlockSize > DFL_BLKSIZE)
1089			defaults->rsrcClumpSize = ROUNDUP(kHFSPlusRsrcClumpFactor * DFL_BLKSIZE, gBlockSize);
1090		else
1091			defaults->rsrcClumpSize = kHFSPlusRsrcClumpFactor * gBlockSize;
1092	} else
1093		defaults->rsrcClumpSize = clumpsizecalc(rsrclumpblks);
1094
1095	if (datclumpblks == 0) {
1096		if (gBlockSize > DFL_BLKSIZE)
1097			defaults->dataClumpSize = ROUNDUP(kHFSPlusRsrcClumpFactor * DFL_BLKSIZE, gBlockSize);
1098		else
1099			defaults->dataClumpSize = kHFSPlusRsrcClumpFactor * gBlockSize;
1100	} else
1101		defaults->dataClumpSize = clumpsizecalc(datclumpblks);
1102
1103	/*
1104	 * The default  b-tree node size is 8K.  However, if the
1105	 * volume is small (< 1 GB) we use 4K instead.
1106	 */
1107	if (!gUserCatNodeSize) {
1108		if ((gBlockSize < HFSOPTIMALBLKSIZE) ||
1109		    ((UInt64)(sectorCount * sectorSize) < (UInt64)0x40000000))
1110			catnodesiz = 4096;
1111	}
1112
1113	if (catclumpblks == 0) {
1114		clumpSize = CalcHFSPlusBTreeClumpSize(gBlockSize, catnodesiz, sectorCount, kHFSCatalogFileID);
1115	}
1116	else {
1117		clumpSize = clumpsizecalc(catclumpblks);
1118
1119		if (clumpSize % catnodesiz != 0)
1120			fatal("c=%ld: clump size is not a multiple of node size\n", clumpSize/gBlockSize);
1121	}
1122	defaults->catalogClumpSize = clumpSize;
1123	defaults->catalogNodeSize = catnodesiz;
1124	defaults->catalogExtsCount = catExtCount;
1125	defaults->catalogStartBlock = catExtStart;
1126
1127	if (gBlockSize < 4096 && gBlockSize < catnodesiz)
1128		warnx("Warning: block size %u is less than catalog b-tree node size %u", (unsigned int)gBlockSize, (unsigned int)catnodesiz);
1129
1130	if (extclumpblks == 0) {
1131		clumpSize = CalcHFSPlusBTreeClumpSize(gBlockSize, extnodesiz, sectorCount, kHFSExtentsFileID);
1132	}
1133	else {
1134		clumpSize = clumpsizecalc(extclumpblks);
1135		if (clumpSize % extnodesiz != 0)
1136			fatal("e=%ld: clump size is not a multiple of node size\n", clumpSize/gBlockSize);
1137	}
1138	defaults->extentsClumpSize = clumpSize;
1139	defaults->extentsNodeSize = extnodesiz;
1140	defaults->extentsExtsCount = extExtCount;
1141	defaults->extentsStartBlock = extExtStart;
1142
1143	if (gBlockSize < extnodesiz)
1144		warnx("Warning: block size %u is less than extents b-tree node size %u", (unsigned int)gBlockSize, (unsigned int)extnodesiz);
1145	if (defaults->extentsExtsCount > 8) {
1146		warnx("Warning:  extents overflow extent requested count %u exceeds maximum 8, capping at 8\n", defaults->extentsExtsCount);
1147		defaults->extentsExtsCount = 8;
1148	}
1149	if (atrclumpblks == 0) {
1150		if (gUserAttrSize) {
1151			clumpSize = 0;
1152		}
1153		else {
1154			clumpSize = CalcHFSPlusBTreeClumpSize(gBlockSize, atrnodesiz, sectorCount, kHFSAttributesFileID);
1155		}
1156	}
1157	else {
1158		clumpSize = clumpsizecalc(atrclumpblks);
1159		if (clumpSize % atrnodesiz != 0)
1160			fatal("a=%ld: clump size is not a multiple of node size\n", clumpSize/gBlockSize);
1161	}
1162	defaults->attributesClumpSize = clumpSize;
1163	defaults->attributesNodeSize = atrnodesiz;
1164	defaults->attributesExtsCount = attrExtCount;
1165	defaults->attributesStartBlock = attrExtStart;
1166
1167	/*
1168	 * Calculate the number of blocks needed for bitmap (rounded up to a multiple of the block size).
1169	 */
1170
1171	/*
1172	 * Figure out how many bytes we need for the given totalBlocks
1173	 * Note: this minimum value may be too large when it counts the
1174	 * space used by the wrapper
1175	 */
1176	totalBlocks = sectorCount / (gBlockSize / sectorSize);
1177
1178	minClumpSize = totalBlocks >> 3;	/* convert bits to bytes by dividing by 8 */
1179	if (totalBlocks & 7)
1180		++minClumpSize;	/* round up to whole bytes */
1181
1182	/* Round up to a multiple of blockSize */
1183	if ((oddBitmapBytes = minClumpSize % gBlockSize))
1184		minClumpSize = minClumpSize - oddBitmapBytes + gBlockSize;
1185
1186	if (bmclumpblks == 0) {
1187		clumpSize = minClumpSize;
1188	}
1189	else {
1190		clumpSize = clumpsizecalc(bmclumpblks);
1191
1192		if (clumpSize < minClumpSize)
1193			fatal("b=%ld: bitmap clump size is too small\n", clumpSize/gBlockSize);
1194	}
1195	defaults->allocationClumpSize = clumpSize;
1196	defaults->allocationExtsCount = blkallocExtCount;
1197	defaults->allocationStartBlock = blkallocExtStart;
1198
1199	defaults->journalInfoBlock = jibStart;
1200	defaults->journalBlock = jnlStart;
1201	defaults->nextAllocBlock = allocStart;
1202
1203	if (gCaseSensitive)
1204		defaults->flags |= kMakeCaseSensitive;
1205
1206	if (gContentProtect)
1207		defaults->flags |= kMakeContentProtect;
1208
1209#ifdef DEBUG_BUILD
1210	if (gProtectLevel)
1211		defaults->protectlevel = gProtectLevel;
1212#endif
1213
1214	if (gNoCreate) {
1215		if (gPartitionSize == 0)
1216			printf("%llu sectors (%u bytes per sector)\n", dip->physTotalSectors, dip->physSectorSize);
1217		printf("HFS Plus format parameters:\n");
1218		printf("\tvolume name: \"%s\"\n", gVolumeName);
1219		printf("\tblock-size: %u\n", defaults->blockSize);
1220		printf("\ttotal blocks: %u\n", totalBlocks);
1221		if (gJournaled)
1222			printf("\tjournal-size: %uk\n", defaults->journalSize/1024);
1223		printf("\tfirst free catalog node id: %u\n", defaults->nextFreeFileID);
1224		printf("\tcatalog b-tree node size: %u\n", defaults->catalogNodeSize);
1225		printf("\tinitial catalog file size: %u\n", defaults->catalogClumpSize);
1226		printf("\textents b-tree node size: %u\n", defaults->extentsNodeSize);
1227		printf("\tinitial extents file size: %u\n", defaults->extentsClumpSize);
1228		printf("\tattributes b-tree node size: %u\n", defaults->attributesNodeSize);
1229		printf("\tinitial attributes file size: %u\n", defaults->attributesClumpSize);
1230		printf("\tinitial allocation file size: %u (%u blocks)\n",
1231			defaults->allocationClumpSize, defaults->allocationClumpSize / gBlockSize);
1232		printf("\tdata fork clump size: %u\n", defaults->dataClumpSize);
1233		printf("\tresource fork clump size: %u\n", defaults->rsrcClumpSize);
1234		if (defaults->flags & kUseAccessPerms) {
1235			printf("\tuser ID: %d\n", (int)defaults->owner);
1236			printf("\tgroup ID: %d\n", (int)defaults->group);
1237			printf("\taccess mask: %o\n", (int)defaults->mask);
1238		}
1239		printf("\tfile system start block: %u\n", defaults->fsStartBlock);
1240	}
1241}
1242
1243
1244static UInt32
1245clumpsizecalc(UInt32 clumpblocks)
1246{
1247	UInt64 clumpsize;
1248
1249	clumpsize = (UInt64)clumpblocks * (UInt64)gBlockSize;
1250
1251	if (clumpsize & (UInt64)(0xFFFFFFFF00000000ULL))
1252		fatal("=%ld: too many blocks for clump size!", clumpblocks);
1253
1254	return ((UInt32)clumpsize);
1255}
1256
1257
1258#define CLUMP_ENTRIES	15
1259
1260short clumptbl[CLUMP_ENTRIES * 3] = {
1261/*
1262 *	    Volume	Attributes	 Catalog	 Extents
1263 *	     Size	Clump (MB)	Clump (MB)	Clump (MB)
1264 */
1265	/*   1GB */	  4,		  4,		 4,
1266	/*   2GB */	  6,		  6,		 4,
1267	/*   4GB */	  8,		  8,		 4,
1268	/*   8GB */	 11,		 11,		 5,
1269	/*
1270	 * For volumes 16GB and larger, we want to make sure that a full OS
1271	 * install won't require fragmentation of the Catalog or Attributes
1272	 * B-trees.  We do this by making the clump sizes sufficiently large,
1273	 * and by leaving a gap after the B-trees for them to grow into.
1274	 *
1275	 * For SnowLeopard 10A298, a FullNetInstall with all packages selected
1276	 * results in:
1277	 * Catalog B-tree Header
1278	 *	nodeSize:          8192
1279	 *	totalNodes:       31616
1280	 *	freeNodes:         1978
1281	 * (used = 231.55 MB)
1282	 * Attributes B-tree Header
1283	 *	nodeSize:          8192
1284	 *	totalNodes:       63232
1285	 *	freeNodes:          958
1286	 * (used = 486.52 MB)
1287	 *
1288	 * We also want Time Machine backup volumes to have a sufficiently
1289	 * large clump size to reduce fragmentation.
1290	 *
1291	 * The series of numbers for Catalog and Attribute form a geometric series.
1292	 * For Catalog (16GB to 512GB), each term is 8**(1/5) times the previous
1293	 * term.  For Attributes (16GB to 512GB), each term is 4**(1/5) times
1294	 * the previous term.  For 1TB to 16TB, each term is 2**(1/5) times the
1295	 * previous term.
1296	 */
1297	/*  16GB */	 64,		 32,		 5,
1298	/*  32GB */	 84,		 49,		 6,
1299	/*  64GB */	111,		 74,		 7,
1300	/* 128GB */	147,		111,		 8,
1301	/* 256GB */	194,		169,		 9,
1302	/* 512GB */	256,		256,		11,
1303	/*   1TB */	294,		294,		14,
1304	/*   2TB */	338,		338,		16,
1305	/*   4TB */	388,		388,		20,
1306	/*   8TB */	446,		446,		25,
1307	/*  16TB */	512,		512,		32
1308};
1309
1310/*
1311 * CalcHFSPlusBTreeClumpSize
1312 *
1313 * This routine calculates the file clump size for either
1314 * the catalog file or the extents overflow file.
1315 */
1316static UInt32
1317CalcHFSPlusBTreeClumpSize(UInt32 blockSize, UInt32 nodeSize, UInt64 sectors, int fileID)
1318{
1319	UInt32 mod = MAX(nodeSize, blockSize);
1320	UInt32 clumpSize;
1321	int column;
1322	int i;
1323
1324	/* Figure out which column of the above table to use for this file. */
1325	switch (fileID) {
1326		case kHFSAttributesFileID:
1327			column = 0;
1328			break;
1329		case kHFSCatalogFileID:
1330			column = 1;
1331			break;
1332		default:
1333			column = 2;
1334			break;
1335	}
1336
1337	/*
1338	 * The default clump size is 0.8% of the volume size. And
1339	 * it must also be a multiple of the node and block size.
1340	 */
1341	if (sectors < 0x200000) {
1342		clumpSize = sectors << 2;	/*  0.8 %  */
1343		if (clumpSize < (8 * nodeSize))
1344			clumpSize = 8 * nodeSize;
1345	} else {
1346		/*
1347		 * XXX This should scale more smoothly!
1348		 */
1349		/* turn exponent into table index... */
1350		for (i = 0, sectors = sectors >> 22;
1351		     sectors && (i < CLUMP_ENTRIES-1);
1352		     ++i, sectors = sectors >> 1);
1353
1354		clumpSize = clumptbl[column + (i) * 3] * 1024 * 1024;
1355	}
1356
1357	/*
1358	 * Round the clump size to a multiple of node and block size.
1359	 * NOTE: This rounds down.
1360	 */
1361	clumpSize /= mod;
1362	clumpSize *= mod;
1363
1364	/*
1365	 * Rounding down could have rounded down to 0 if the block size was
1366	 * greater than the clump size.  If so, just use one block or node.
1367	 */
1368	if (clumpSize == 0)
1369		clumpSize = mod;
1370
1371	return (clumpSize);
1372}
1373
1374
1375/* VARARGS */
1376void
1377#if __STDC__
1378fatal(const char *fmt, ...)
1379#else
1380fatal(fmt, va_alist)
1381	char *fmt;
1382	va_dcl
1383#endif
1384{
1385	va_list ap;
1386
1387#if __STDC__
1388	va_start(ap, fmt);
1389#else
1390	va_start(ap);
1391#endif
1392	if (fcntl(STDERR_FILENO, F_GETFL) < 0) {
1393		openlog(progname, LOG_CONS, LOG_DAEMON);
1394		vsyslog(LOG_ERR, fmt, ap);
1395		closelog();
1396	} else {
1397		vwarnx(fmt, ap);
1398	}
1399	va_end(ap);
1400	exit(1);
1401	/* NOTREACHED */
1402}
1403
1404
1405void usage()
1406{
1407	fprintf(stderr, "usage: %s [-N [partition-size]] [hfsplus-options] special-device\n", progname);
1408
1409	fprintf(stderr, "  options:\n");
1410	fprintf(stderr, "\t-N do not create file system, just print out parameters\n");
1411	fprintf(stderr, "\t-s use case-sensitive filenames (default is case-insensitive)\n");
1412
1413	fprintf(stderr, "  where hfsplus-options are:\n");
1414	fprintf(stderr, "\t-J [journal-size] make this HFS+ volume journaled\n");
1415	fprintf(stderr, "\t-D journal-dev use 'journal-dev' for an external journal\n");
1416	fprintf(stderr, "\t-G group-id (for root directory)\n");
1417	fprintf(stderr, "\t-U user-id (for root directory)\n");
1418	fprintf(stderr, "\t-M octal access-mask (for root directory)\n");
1419	fprintf(stderr, "\t-b allocation block size (4096 optimal)\n");
1420	fprintf(stderr, "\t-c clump size list (comma separated)\n");
1421	fprintf(stderr, "\t\ta=blocks (attributes file)\n");
1422	fprintf(stderr, "\t\tb=blocks (bitmap file)\n");
1423	fprintf(stderr, "\t\tc=blocks (catalog file)\n");
1424	fprintf(stderr, "\t\td=blocks (user data fork)\n");
1425	fprintf(stderr, "\t\te=blocks (extents file)\n");
1426	fprintf(stderr, "\t\tr=blocks (user resource fork)\n");
1427	fprintf(stderr, "\t-i starting catalog node id\n");
1428	fprintf(stderr, "\t-n b-tree node size list (comma separated)\n");
1429	fprintf(stderr, "\t\te=size (extents b-tree)\n");
1430	fprintf(stderr, "\t\tc=size (catalog b-tree)\n");
1431	fprintf(stderr, "\t\ta=size (attributes b-tree)\n");
1432	fprintf(stderr, "\t-v volume name (in ascii or UTF-8)\n");
1433#ifdef DEBUG_BUILD
1434	fprintf(stderr, "\t-E extent count list (comma separated)\n");
1435	fprintf(stderr, "\t\ta=count (attributes file)\n");
1436	fprintf(stderr, "\t\tb=count (bitmap file)\n");
1437	fprintf(stderr, "\t\tc=count (catalog file)\n");
1438	fprintf(stderr, "\t\te=count (extents file)\n");
1439	fprintf(stderr, "\t-a <num>[,list] metadata start allocation block, all btrees and journal will be created starting at this allocation block offset\n");
1440	fprintf(stderr, "\t\tlist is as with -E above, plus:\n");
1441	fprintf(stderr, "\t\tj=addr (JournalInfoBlock)\n");
1442	fprintf(stderr, "\t\tJ=addr (Journal)\n");
1443	fprintf(stderr, "\t\tN=addr (Next Allocation Block)\n");
1444	fprintf(stderr, "\t\tExample: -a 100,e=200,c=500\n");
1445#endif
1446
1447	fprintf(stderr, "  examples:\n");
1448	fprintf(stderr, "\t%s -v Untitled /dev/rdisk0s7 \n", progname);
1449	fprintf(stderr, "\t%s -v Untitled -n c=4096,e=1024 /dev/rdisk0s7 \n", progname);
1450	fprintf(stderr, "\t%s -v Untitled -c b=64,c=1024 /dev/rdisk0s7 \n\n", progname);
1451
1452	exit(1);
1453}
1454