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
41void
42PrintValue(const void *key, const void *value, void *context) {
43	int key_len, value_len;
44	const CFStringRef kStr = key;
45	const CFTypeRef kVal = value;
46	char *buf = NULL;
47	int32_t val;
48	char *intFmt = "%d\n";
49
50	if (CFGetTypeID(kStr) != CFStringGetTypeID()) {
51		warnx("PrintDictionary:  key type is not a string");
52		return;
53	}
54
55	if (CFStringCompare(kStr, CFSTR("owner-mode"), 0) == kCFCompareEqualTo) {
56		intFmt = "0%o\n";
57	} else if (!gVerbose && (CFStringCompare(kStr, CFSTR("Base"), 0) == kCFCompareEqualTo ||
58		CFStringCompare(kStr, CFSTR("Size"), 0) == kCFCompareEqualTo)) {
59		return;
60	}
61
62	key_len = CFStringGetLength(kStr);
63	buf = malloc(key_len * 2);
64	if (!buf) {
65		warnx("PrintDictionary:  unable to allocate buffer for key");
66		goto out;
67	}
68	if (!CFStringGetCString(kStr, buf, key_len * 2, kCFStringEncodingASCII)) {
69		warnx("PrintDictionary:  unable to get key as C string");
70		goto out;
71	}
72	printf("\t%s = ", buf);
73	free(buf); buf = NULL;
74
75	if (CFGetTypeID(kVal) == CFStringGetTypeID()) {
76		value_len = CFStringGetLength(kVal);
77		buf = malloc(value_len * 2);
78		if (buf == NULL) {
79			warnx("PrintDictionary:  unable to allocate buffer for value");
80			printf("* * * ERROR * * *\n");
81			goto out;
82		}
83		if (!CFStringGetCString(kVal, buf, value_len * 2, kCFStringEncodingASCII)) {
84			warnx("PrintDictionary: unable to get value as C String");
85			printf("* * * ERROR * * *\n");
86			goto out;
87		}
88		printf("\"%s\"\n", buf);
89		free(buf); buf = NULL;
90	} else if (CFGetTypeID(kVal) == CFNumberGetTypeID()) {
91		if (!CFNumberGetValue(kVal, kCFNumberSInt32Type, &val)) {
92			warnx("PrintDictionary: unable to get value as 32-bit number");
93			printf("* * * ERROR * * *\n");
94			goto out;
95		}
96		printf(intFmt, val);
97	}
98
99out:
100	if (buf)
101		free(buf);
102	return;
103}
104
105void
106doProps(const char *dev, char **args) {
107	CFMutableDictionaryRef md = nil;
108	CFDictionaryRef old;
109	CFStringRef cfStr = nil;
110	CFNumberRef cfNum = nil;
111	int changes = 0;
112
113	int i;
114
115	old = ReadMetadata(dev);
116	if (old == nil) {
117		warnx("doProps:  cannot get metadata for device %s", dev);
118		goto out;
119	}
120
121	md = CFDictionaryCreateMutableCopy(nil, 0, old);
122
123	if (md == nil) {
124		warnx("cannot create dictionary in doProps");
125		goto out;
126	}
127
128	if (args[0] == NULL) {
129		CFDictionaryApplyFunction(old, &PrintValue, NULL);
130		goto out;
131	}
132
133	for (i = 0; args[i]; i++) {
134		char *arg = args[i];
135		CFTypeRef v;
136		CFStringRef k;
137
138		if (parseProperty(arg, &k, &v) > 0) {
139			if (v == nil) {
140				/* No value, so just print it out */
141				v = CFDictionaryGetValue(old, k);
142				if (v == nil) {
143					warnx("Property `%s' does not exist in metadata", arg);
144				} else {
145					PrintValue(k, v, NULL);
146				}
147				CFRelease(k);
148				continue;
149			}
150			// We have a key and a value, so we set them
151			CFDictionarySetValue(md, k, v);
152			printf("\tProperty %s\n", arg);
153			CFRelease(k);
154			CFRelease(v);
155			changes++;
156		}
157	}
158
159	if (gDebug) {
160		CFDataRef data;
161		int len;
162		char *cp;
163		data = CFPropertyListCreateXMLData(nil, (CFPropertyListRef)md);
164		len = CFDataGetLength(data);
165		cp = (char*)CFDataGetBytePtr(data);
166		write (2, cp, len);
167		CFRelease(data);
168
169	}
170	if (changes) {
171		if (WriteMetadata(dev, md) != 1) {
172			errx(3, "doProps:  cannot write metadata");
173		}
174	}
175out:
176	if (old)
177		CFRelease(old);
178	if (md)
179		CFRelease(md);
180	if (cfStr)
181		CFRelease(cfStr);
182	if (cfNum)
183		CFRelease(cfNum);
184
185	return;
186}
187
188