1/*
2 * Copyright (c) 2004 Apple Computer, 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#include <stdio.h>
25#include <string.h>
26#include <stdlib.h>
27#include <limits.h>
28#include <errno.h>
29#include <err.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <pwd.h>
34#include <grp.h>
35#include <unistd.h>
36
37#include <CoreFoundation/CoreFoundation.h>
38
39#include "util.h"
40
41static uint64_t
42ParseSize(char *str) {
43	uint64_t size, retval;
44	char *endptr;
45	uint64_t mult = 1;
46
47	fprintf(stderr, "ParseSize(%s)\n", str);
48
49	errno = 0;
50	size = strtoq(str, &endptr, 10);
51	if (errno != 0) {
52		warn("cannot parse `%s': ", str);
53		return -1;
54	}
55
56	if (endptr && *endptr != 0) {
57		if (strlen(endptr) != 1) {
58			warnx("cannot parse `%s': unknown suffix `%s'",
59				str, endptr);
60			return -1;
61		}
62		switch (*endptr) {
63			case 'b': case 'B':
64				mult = 512; break;
65			case 'k': case 'K':
66				mult = 1024; break;
67			case 'm': case 'M':
68				mult = 1024 * 1024; break;
69			case 'g': case 'G':
70				mult = 1024 * 1024 * 1024; break;
71			default:
72				warnx("cannot parse `%s': unknown suffix `%s'",
73					str, endptr);
74				return -1;
75		}
76	}
77	retval = size * mult;
78	return retval;
79}
80
81void
82doCreate(const char *dev, char **args) {
83	uint64_t size = 128 * 1024;	// Default size of metadata area
84	CFMutableDictionaryRef md = nil;
85	CFStringRef cfStr = nil;
86	CFNumberRef cfNum = nil;
87	int blocksize = GetBlockSize(dev);
88	uint64_t disksize = GetDiskSize(dev);
89
90	int i;
91
92	if (blocksize == 0) {
93		errx(4, "doCreate:  Cannot get valid blocksize for device %s", dev);
94	}
95	if (disksize == 0) {
96		errx(5, "doCreate:  Cannot get valid disk size for device %s", dev);
97	}
98
99
100	md = CFDictionaryCreateMutable(nil, 0, nil, nil);
101	if (md == nil) {
102		warnx("cannot create dictionary in doCreate");
103		goto out;
104	}
105
106	for (i = 0; args[i]; i++) {
107		char *arg = args[i];
108		CFTypeRef v;
109		CFStringRef k;
110
111		if (parseProperty(arg, &k, &v) > 0) {
112			if (v == nil) {
113				warnx("cannot parse `%s': tag must have a value", arg);
114bad:
115				CFRelease(k);
116				continue;
117			}
118			if (CFStringCompare(k, CFSTR("-msize"), 0)
119				== kCFCompareEqualTo) {
120				if (CFGetTypeID(v) == CFStringGetTypeID()) {
121					int len = CFStringGetLength(v);
122					char buf[len*2];
123
124					memset(buf, 0, sizeof(buf));
125					if (CFStringGetCString(v, buf, sizeof(buf), kCFStringEncodingASCII) == FALSE) {
126						warnx("cannot convert msize to string!");
127						goto bad;
128					}
129					size = ParseSize(buf);
130				} else if (CFGetTypeID(v) != CFNumberGetTypeID()) {
131					warnx("-msize value must be a number");
132					goto bad;
133				} else {
134					CFNumberGetValue(v, kCFNumberSInt64Type, &size);
135				}
136				CFRelease(k);
137				CFRelease(v);
138				continue;
139			}
140			CFDictionaryAddValue(md, k, v);
141		}
142	}
143
144	if (size > 0) {
145		disksize = disksize - size;
146		cfNum = CFNumberCreate(NULL, kCFNumberSInt64Type, &size);
147		if (cfNum == NULL) {
148			errx(6, "doCreate:  cannot create base number");
149		}
150		CFDictionaryAddValue(md, CFSTR("Base"), cfNum);
151		CFRelease(cfNum);
152		cfNum = CFNumberCreate(NULL, kCFNumberSInt64Type, &disksize);
153		if (cfNum == NULL) {
154			errx(7, "doCreate:  cannot create size number");
155		}
156		CFDictionaryAddValue(md, CFSTR("Size"), cfNum);
157		if (gDebug) {
158			CFDataRef data;
159			int len;
160			char *cp;
161			data = CFPropertyListCreateXMLData(nil, (CFPropertyListRef)md);
162			len = CFDataGetLength(data);
163			cp = (char*)CFDataGetBytePtr(data);
164			fprintf(stderr, "Size = %qu bytes\n", size);
165			write (2, cp, len);
166			CFRelease(data);
167
168		}
169		// Now need to put the metadata in the partition
170		if (InitialMetadata(dev, md, size) == -1) {
171			errx(3, "Cannot write initial metadata to device %s", dev);
172		}
173	}
174out:
175	if (md)
176		CFRelease(md);
177	if (cfStr)
178		CFRelease(cfStr);
179	if (cfNum)
180		CFRelease(cfNum);
181
182	return;
183}
184
185