1/* 2 * Copyright (c) 2001-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * The contents of this file constitute Original Code as defined in and 7 * are subject to the Apple Public Source License Version 1.1 (the 8 * "License"). You may not use this file except in compliance with the 9 * License. Please obtain a copy of the License at 10 * http://www.apple.com/publicsource and read it before using this file. 11 * 12 * This Original Code and all software distributed under the License are 13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the 17 * License for the specific language governing rights and limitations 18 * under the License. 19 * 20 * @APPLE_LICENSE_HEADER_END@ 21 */ 22 23 24#include <stdio.h> 25#include <stdlib.h> 26#include <unistd.h> 27#include <getopt.h> 28#include <sys/fcntl.h> 29 30#include <mach/mach.h> 31 32#include <CoreFoundation/CoreFoundation.h> 33 34#include <IOKit/IOKitLib.h> 35#include <IOKit/IOCFUnserialize.h> 36#include <IOKit/IOMessage.h> 37 38#include <MediaKit/MKMedia.h> 39#include <MediaKit/MKMediaAccess.h> 40 41#include "AppleRAIDUserLib.h" 42#include "AppleRAIDMember.h" // for V2 header 43 44#define AUTO_YES 1 45#define AUTO_NO 2 46 47static int autoRebuild = 0; 48static UInt64 blockSize = 0; 49static bool extents = false; 50static char * hint = 0; 51static char * nickname = 0; 52static int quickRebuild = 0; 53static UInt64 timeout = 0; 54static bool verbose = false; 55static UInt64 volSize = 0; 56 57static void 58usage() 59{ 60 printf("\n"); 61 printf("usage:\n"); 62 printf("\n"); 63 printf("artest --list\n"); 64 printf("artest --lvlist [--extents] <lv uuid | lvg uuid>\n"); 65 printf("\n"); 66 printf("artest --create --name <nickname> --level <level> <options> disk1s3 disk2s3 disk3s3 ...\n"); 67 printf("artest --destroy <set uuid>\n"); 68 printf("\n"); 69 printf("artest --add <set uuid> disk1s3 ...\n"); 70 printf("artest --spare <set uuid> disk1s3 ...\n"); 71 printf("artest --remove <set uuid> <member uuid> ...\n"); 72 printf("artest --modify <set uuid> <options>\n"); 73 printf("\n"); 74 printf("artest --lvcreate <lvg uuid> <lvoptions>\n"); 75 printf("artest --lvdestroy <lv uuid>\n"); 76 printf("\n"); 77 printf("artest --lvmodify <lv uuid> <lvoptions>\n"); 78 printf("artest --lvresize <lv uuid> [--size <number>]\n"); 79 printf("artest --lvsnap <lv uuid> [--size <number>] --level=\"snap ro\"|\"snap rw\">\n"); 80 printf("\n"); 81 printf("artest --erase disk1s3 disk2s3 disk3s3 ...\n"); 82 printf("artest --header disk1s3 disk2s3 disk3s3 ...\n"); 83 printf("\n"); 84 printf("parameters:\n"); 85 printf(" <uuid> = XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\n"); 86 printf(" <nickname> = \"the volume name\"\n"); 87 printf(" <level> = stripe, mirror, concat, lvg\n"); 88 printf(" <hint> = Apple_HFS, RAIDNoMedia, RAIDNoFS\n"); 89 printf(" <options> = [--auto-rebuild=Yes,No] [--block-size=0x8000] [--hint=<hint>]\n"); 90 printf(" <options> = [--name=<nickname>] [--timeout=30] [--quick-rebuild=Yes]\n"); 91 printf(" <lvoptions> = [--level=concat] [--hint=<hint>] [--name=<nickname>] [--size 0xXXXXXXXXXXXXXXXX]\n"); 92 printf("\n"); 93 printf("global options:\n"); 94 printf(" --verbose\n"); 95 printf(" --watch (also a command)\n"); 96} 97 98 99// there must be something like this already? 100 101static void 102CFPrintf(CFStringRef format, ...) 103{ 104 CFStringRef cfstring; 105 va_list argList; 106 107 va_start(argList, format); 108 cfstring = CFStringCreateWithFormatAndArguments(NULL, NULL, format, argList); 109 va_end(argList); 110 111 CFIndex cfstringSize = CFStringGetLength(cfstring); 112 CFIndex stringSize = CFStringGetMaximumSizeForEncoding(cfstringSize, kCFStringEncodingUTF8) + 1; 113 char *string = malloc(stringSize); 114 if (CFStringGetCString(cfstring, string, stringSize, kCFStringEncodingUTF8)) { 115 printf("%s", string); 116 } 117 free(string); 118} 119 120 121#define PMROptions (PMEXTENDEDMODE | PMSECTORIZE | PMSORTMAP) 122 123#define kRAID_ONLINE "Apple_RAID" 124#define kRAID_OFFLINE "Apple_RAID_Offline" 125 126// switches partition type 127 128static bool 129switchPartition(char * diskName, char * partitionType) 130{ 131 char wholeDevicePath[256]; 132 sprintf(wholeDevicePath, "/dev/%s", diskName); 133 134 unsigned int partitionNumber = 0; 135 char * c = wholeDevicePath + 5 + 4; // skip over "/dev/disk" 136 while (*c != 's' && *c++); // look for 's' 137 if (*c == 's') { 138 *c = 0; // clip off remainder 139 sscanf(c+1, "%u", &partitionNumber); // get partition number 140 } 141 if (!partitionNumber) return true; // just assume it is a raid disk 142 143#define LIVERAID 144#ifdef LIVERAID 145 char * optionString = "<dict> <key>Writable</key> <true/> <key>Shared Writer</key> <true/></dict>"; 146#else 147 char * optionString = "<dict> <key>Writable</key> <true/> </dict>"; 148#endif 149 CFDictionaryRef options = IOCFUnserialize(optionString, kCFAllocatorDefault, 0, NULL); 150 if (!options) exit(1); 151 152 int32_t err; 153 MKMediaRef device = MKMediaCreateWithPath(nil, wholeDevicePath, options, &err); 154 CFRelease(options); 155 if (!device || err) return false; 156 157 options = NULL; 158 MKStatus err2; 159 CFMutableDictionaryRef media = MKCFReadMedia(options, device, &err2); 160 if (!media || err2) goto Failure; 161 162 // find and extract the 'Schemes' array 163 CFMutableArrayRef Schemes = (CFMutableArrayRef) CFDictionaryGetValue(media, CFSTR("Schemes")); 164 if (!Schemes) goto Failure; 165 166 // DMTool just grabs the first "default" scheme, so do the same 167 CFMutableDictionaryRef Scheme = (CFMutableDictionaryRef) CFArrayGetValueAtIndex(Schemes, 0); 168 if (!Scheme) goto Failure; 169 170 // Then find and extract the 'Sections' array of that scheme: 171 CFMutableArrayRef Sections = (CFMutableArrayRef) CFDictionaryGetValue(Scheme, CFSTR("Sections")); 172 if (!Sections) goto Failure; 173 174 // Every scheme can have multiple sections to it, we need to find the 'MAP' section: 175 CFMutableDictionaryRef Section = (CFMutableDictionaryRef) CFArrayDictionarySearch(Sections, CFSTR("ID"), CFSTR("MAP")); 176 if (!Section) goto Failure; 177 178 // Then find and extract the 'Partitions' array of that section: 179 CFMutableArrayRef Partitions = (CFMutableArrayRef) CFDictionaryGetValue(Section, CFSTR("Partitions")); 180 if (!Partitions) goto Failure; 181 182 CFNumberRef partitionIndex = CFNumberCreate(nil, kCFNumberSInt32Type, &partitionNumber); 183 if (!partitionIndex) goto Failure; 184 CFMutableDictionaryRef Partition = (CFMutableDictionaryRef) CFArrayDictionarySearch(Partitions, CFSTR("Partition ID"), partitionIndex); 185 if (!Partition) goto Failure; 186 187 // change the partition type (finally!) 188 CFStringRef Type = CFStringCreateWithCString(nil, partitionType, kCFStringEncodingUTF8); 189 if (!Type) goto Failure; 190 CFDictionarySetValue(Partition, CFSTR("Type"), Type); 191 192 CFMutableDictionaryRef woptions = CFDictionaryCreateMutable(kCFAllocatorDefault, 193 2, 194 &kCFTypeDictionaryKeyCallBacks, 195 &kCFTypeDictionaryValueCallBacks); 196 if (!woptions) goto Failure; 197 CFDictionarySetValue(woptions, CFSTR("Retain existing content"), kCFBooleanTrue); 198 CFDictionarySetValue(woptions, CFSTR("Direct Mode"), kCFBooleanTrue); 199 200 err2 = MKCFWriteMedia(media, nil, nil, woptions, device); 201 202 MKCFDisposeMedia(media); 203 CFRelease(woptions); 204 CFRelease(device); 205 return !err2; 206 207Failure: 208 if (media) MKCFDisposeMedia(media); 209 if (device) CFRelease(device); 210 211 return false; 212} 213 214static void 215addMember(char * uuid, CFStringRef type, int argc, char* argv[]) 216{ 217 if (argc < 1) { 218 usage(); 219 exit(1); 220 } 221 222 CFStringRef setUUID = CFStringCreateWithCString(kCFAllocatorDefault, uuid, kCFStringEncodingUTF8); 223 if (!setUUID) exit(1); 224 225 CFMutableDictionaryRef setInfo = AppleRAIDGetSetProperties(setUUID); 226 if (!setInfo) { 227 printf("addMember - failed to find RAID set \"%s\"\n", uuid); 228 exit(1); 229 } 230 231 int partitionCount = argc; 232 char **firstPartition = argv; 233 234 while (argc--) { 235 printf("adding partition \"%s\"\n", *argv); 236 CFStringRef partitionName = CFStringCreateWithCString(kCFAllocatorDefault, *argv, kCFStringEncodingUTF8); 237 238 bool success = switchPartition(*argv, kRAID_OFFLINE); 239 if (!success) { 240 printf("switching the partition on \"%s\" to %s FAILED.\n", *argv, kRAID_OFFLINE); 241 exit(1); 242 } 243 244 AppleRAIDMemberRef member = AppleRAIDAddMember(setInfo, partitionName, type); 245 if (!member) { 246 printf("addMember - there was problem adding partition \"%s\"\n", *argv); 247 exit(1); 248 } 249 250 argv++; 251 } 252 253 printf("updating set \"%s\".\n", uuid); 254 AppleRAIDSetRef set = AppleRAIDUpdateSet(setInfo); 255 CFRelease(setInfo); 256 257 if (!set) { 258 printf("something went wrong adding members to the set\n"); 259 exit(1); 260 } 261 262 while (partitionCount--) { 263 printf("switching the partition on \"%s\" to %s.\n", *firstPartition, kRAID_ONLINE); 264 bool success = switchPartition(*firstPartition, kRAID_ONLINE); 265 if (!success) { 266 printf("switching the partition on \"%s\" to %s FAILED.\n", *firstPartition, kRAID_ONLINE); 267 exit(1); 268 } 269 270 firstPartition++; 271 } 272 273 // at this point the code should wait for notifications that members and the set are available 274} 275 276static void 277createSet(char * levelCString, char * nameCString, int argc, char* argv[]) 278{ 279 if (!levelCString || !nameCString || argc < 2) { 280 usage(); 281 exit(1); 282 } 283 284 CFStringRef level = CFStringCreateWithCString(kCFAllocatorDefault, levelCString, kCFStringEncodingUTF8); 285 CFStringRef name = CFStringCreateWithCString(kCFAllocatorDefault, nameCString, kCFStringEncodingUTF8); 286 if (!level || !name) exit(1); 287 288 // get list of available raid set descriptions 289 CFMutableArrayRef descriptionArray = AppleRAIDGetSetDescriptions(); 290 291 CFIndex dCount = CFArrayGetCount(descriptionArray); 292 CFIndex dIndex = 0; 293 CFStringRef dLevel = 0; 294 for (dIndex = 0; dIndex < dCount; dIndex++) { 295 CFMutableDictionaryRef setDescription = (CFMutableDictionaryRef)CFArrayGetValueAtIndex(descriptionArray, dIndex); 296 dLevel = (CFStringRef)CFDictionaryGetValue(setDescription, CFSTR(kAppleRAIDLevelNameKey)); 297 if (!dLevel) break; 298 299 if (CFStringCompare(dLevel, level, kCFCompareCaseInsensitive) == kCFCompareEqualTo) break; 300 dLevel = 0; 301 } 302 if (dLevel == 0) { 303 printf("raid level \"%s\" is not valid?.\n", levelCString); 304 exit(1); 305 } 306 307 CFMutableDictionaryRef setInfo = AppleRAIDCreateSet(dLevel, name); 308 if (!setInfo) exit(1); 309 310 char **firstPartition = argv; 311 int partitionCount = argc; 312 313 while (argc--) { 314 printf("adding partition \"%s\"\n", *argv); 315 CFStringRef partitionName = CFStringCreateWithCString(kCFAllocatorDefault, *argv, kCFStringEncodingUTF8); 316 317 AppleRAIDMemberRef member = AppleRAIDAddMember(setInfo, partitionName, CFSTR(kAppleRAIDMembersKey)); 318 if (!member) { 319 printf("there was problem adding partition \"%s\"\n", *argv); 320 exit(1); 321 } 322 CFShow(member); 323 324 bool success = switchPartition(*argv, kRAID_OFFLINE); 325 if (!success) { 326 printf("switching the partition on \"%s\" to %s FAILED.\n", *argv, kRAID_OFFLINE); 327 exit(1); 328 } 329 330 argv++; 331 } 332 333 if (autoRebuild == AUTO_YES) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetAutoRebuildKey), (void *)kCFBooleanTrue); 334 if (quickRebuild == AUTO_YES) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetQuickRebuildKey), (void *)kCFBooleanTrue); 335 if (blockSize) { 336 CFNumberRef blockSizeCF = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &blockSize); 337 if (blockSizeCF) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDChunkSizeKey), (void *)blockSizeCF); 338 } 339 if (hint) { 340 CFStringRef hintCF = CFStringCreateWithCString(kCFAllocatorDefault, hint, kCFStringEncodingUTF8); 341 if (hintCF) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetContentHintKey), (void *)hintCF); 342 } 343 if (timeout) { 344 CFNumberRef timeoutCF = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &timeout); 345 if (timeoutCF) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetTimeoutKey), (void *)timeoutCF); 346 } 347 348 printf("creating the set \"%s\".\n", nameCString); 349 AppleRAIDSetRef set = AppleRAIDUpdateSet(setInfo); 350 351 CFPrintf(CFSTR("created set %@\n"), set); 352 CFRelease(setInfo); 353 354 if (!set) { 355 printf("something went wrong creating the set\n"); 356 exit(0); 357 } 358 359 while (partitionCount--) { 360 printf("switching the partition on \"%s\" to %s.\n", *firstPartition, kRAID_ONLINE); 361 bool success = switchPartition(*firstPartition, kRAID_ONLINE); 362 if (!success) { 363 printf("switching the partition on \"%s\" to %s FAILED.\n", *firstPartition, kRAID_ONLINE); 364 exit(1); 365 } 366 367 firstPartition++; 368 } 369 370 // at this point the code should wait for notifications that members and the set are available 371} 372 373static void 374destroySet(char * nameCString, int argc, char* argv[]) 375{ 376 if (!nameCString || argc) { 377 usage(); 378 exit(1); 379 } 380 381 CFStringRef setUUID = CFStringCreateWithCString(kCFAllocatorDefault, nameCString, kCFStringEncodingUTF8); 382 if (!setUUID) exit(1); 383 384 bool success = AppleRAIDDestroySet(setUUID); 385 if (!success) { 386 printf("there was a problem destroying the set %s.\n", nameCString); 387 } 388} 389 390 391static void 392erasePartition(int argc, char* argv[]) 393{ 394 if (argc < 1) { 395 usage(); 396 exit(1); 397 } 398 399 while (argc--) { 400 401 printf("switching the partition type on \"%s\" to %s.\n", *argv, kRAID_OFFLINE); 402 bool success = switchPartition(*argv, kRAID_OFFLINE); 403 if (!success) { 404 printf("switching partition type FAILED.\n"); 405 } 406 407 printf("erasing raid headers on partition \"%s\"\n", *argv); 408 CFStringRef partitionName = CFStringCreateWithCString(kCFAllocatorDefault, *argv, kCFStringEncodingUTF8); 409 success = AppleRAIDRemoveHeaders(partitionName); 410 if (!success) { 411 printf("erasing the raid headers on partition \"%s\" FAILED.\n", *argv); 412 } 413 414 argv++; 415 } 416} 417 418static void 419dumpHeader(int argc, char* argv[]) 420{ 421 if (argc < 1) { 422 usage(); 423 exit(1); 424 } 425 426 while (argc--) { 427 428// printf("dumping the raid header on \"%s\".\n", *argv); 429 430 CFStringRef partitionName = CFStringCreateWithCString(kCFAllocatorDefault, *argv, kCFStringEncodingUTF8); 431 CFDataRef data = AppleRAIDDumpHeader(partitionName); 432 433 if (data) { 434 AppleRAIDHeaderV2 * header = (AppleRAIDHeaderV2 *)CFDataGetBytePtr(data); 435 if (header) printf("%s\n", header->plist); 436 } 437 438 argv++; 439 } 440} 441 442static void 443dumpSetProperties(CFMutableDictionaryRef set) 444{ 445 CFPrintf(CFSTR("\n%@\n"), CFDictionaryGetValue(set, CFSTR(kAppleRAIDSetUUIDKey))); 446 CFPrintf(CFSTR("\t\"%@\" type = %@ /dev/%@\n"), 447 CFDictionaryGetValue(set, CFSTR(kAppleRAIDSetNameKey)), 448 CFDictionaryGetValue(set, CFSTR(kAppleRAIDLevelNameKey)), 449 CFDictionaryGetValue(set, CFSTR("BSD Name"))); 450 CFPrintf(CFSTR("\tstatus = %@, sequence = %@\n"), 451 CFDictionaryGetValue(set, CFSTR(kAppleRAIDStatusKey)), 452 CFDictionaryGetValue(set, CFSTR(kAppleRAIDSequenceNumberKey))); 453 CFPrintf(CFSTR("\tchunk count = %@, chunk size = %@\n"), 454 CFDictionaryGetValue(set, CFSTR(kAppleRAIDChunkCountKey)), 455 CFDictionaryGetValue(set, CFSTR(kAppleRAIDChunkSizeKey))); 456 457 CFStringRef level = CFDictionaryGetValue(set, CFSTR(kAppleRAIDLevelNameKey)); 458 if (CFStringCompare(level, CFSTR("mirror"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 459 CFPrintf(CFSTR("\tcontent hint = %@, auto = %@, quick = %@, timeout = %@\n"), 460 CFDictionaryGetValue(set, CFSTR(kAppleRAIDSetContentHintKey)), 461 CFDictionaryGetValue(set, CFSTR(kAppleRAIDSetAutoRebuildKey)), 462 CFDictionaryGetValue(set, CFSTR(kAppleRAIDSetQuickRebuildKey)), 463 CFDictionaryGetValue(set, CFSTR(kAppleRAIDSetTimeoutKey))); 464 } else if (CFStringCompare(level, CFSTR("LVG"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 465 CFPrintf(CFSTR("\tcontent hint = %@, lv count = %@, free space %@\n"), 466 CFDictionaryGetValue(set, CFSTR(kAppleRAIDSetContentHintKey)), 467 CFDictionaryGetValue(set, CFSTR(kAppleRAIDLVGVolumeCountKey)), 468 CFDictionaryGetValue(set, CFSTR(kAppleRAIDLVGFreeSpaceKey))); 469 } else { 470 CFPrintf(CFSTR("\tcontent hint = %@\n"), CFDictionaryGetValue(set, CFSTR(kAppleRAIDSetContentHintKey))); 471 } 472 473 if (verbose) CFShow(set); 474} 475 476static void 477dumpMemberProperties(CFMutableDictionaryRef member) 478{ 479 CFPrintf(CFSTR("\t%@\n"), CFDictionaryGetValue(member, CFSTR(kAppleRAIDMemberUUIDKey))); 480 CFPrintf(CFSTR("\t\tmember index = %@, sequence = %@, /dev/%@\n"), 481 CFDictionaryGetValue(member, CFSTR(kAppleRAIDMemberIndexKey)), 482 CFDictionaryGetValue(member, CFSTR(kAppleRAIDSequenceNumberKey)), 483 CFDictionaryGetValue(member, CFSTR("BSD Name"))); 484 CFPrintf(CFSTR("\t\tstatus = %@, chunk count = %@, rebuild = %@\n"), 485 CFDictionaryGetValue(member, CFSTR(kAppleRAIDMemberStatusKey)), 486 CFDictionaryGetValue(member, CFSTR(kAppleRAIDChunkCountKey)), 487 CFDictionaryGetValue(member, CFSTR(kAppleRAIDRebuildStatus))); 488 489 if (verbose) CFShow(member); 490} 491 492static void 493listRAIDSets() 494{ 495 UInt32 filter = kAppleRAIDAllSets; 496 CFMutableArrayRef theList = AppleRAIDGetListOfSets(filter); 497 CFIndex setCount = theList ? CFArrayGetCount(theList) : 0; 498 499 printf("AppleRAIDGetListOfSets found %d sets\n", (int)setCount); fflush(stdout); 500 501 // get each set's properties 502 CFIndex i; 503 for (i=0; i < setCount; i++) { 504 505 CFStringRef setName = (CFStringRef)CFArrayGetValueAtIndex(theList, i); 506 if (setName) { 507 CFMutableDictionaryRef setProp = AppleRAIDGetSetProperties(setName); 508 if (!setProp) { 509 CFPrintf(CFSTR("%@\n\t(lookup failed)\n"), setName); 510 continue; 511 } 512 dumpSetProperties(setProp); 513 514 // get each member's properties 515 bool spares = false; 516 CFMutableArrayRef members = (CFMutableArrayRef)CFDictionaryGetValue(setProp, CFSTR(kAppleRAIDMembersKey)); 517 CFIndex j, memberCount = members ? CFArrayGetCount(members) : 0; 518 519 printf("members (%d):\n", (int)memberCount); 520 521 again: 522 for (j=0; j < memberCount; j++) { 523 524 CFStringRef memberName = (CFStringRef)CFArrayGetValueAtIndex(members, j); 525 if (memberName) { 526 CFMutableDictionaryRef memberProp = AppleRAIDGetMemberProperties(memberName); 527 if (memberProp) { 528 dumpMemberProperties(memberProp); 529 CFRelease(memberProp); 530 } else { 531 CFPrintf(CFSTR("\t%@\n\t\t(lookup failed)\n"), memberName); 532 } 533 } 534 } 535 536 if (!spares) { 537 members = (CFMutableArrayRef)CFDictionaryGetValue(setProp, CFSTR(kAppleRAIDSparesKey)); 538 memberCount = members ? CFArrayGetCount(members) : 0; 539 if (memberCount) printf("spares: (%d)\n", (int)memberCount); 540 spares = true; 541 goto again; 542 } 543 spares = false; 544 CFRelease(setProp); 545 } 546 } 547 if (theList) CFRelease(theList); 548} 549 550static void 551modifySet(char * setUUIDCString, int argc, char* argv[]) 552{ 553 if (!setUUIDCString || argc) { 554 usage(); 555 exit(1); 556 } 557 558 CFStringRef setUUID = CFStringCreateWithCString(kCFAllocatorDefault, setUUIDCString, kCFStringEncodingUTF8); 559 if (!setUUID) exit(1); 560 561 CFMutableDictionaryRef setInfo = AppleRAIDGetSetProperties(setUUID); 562 if (!setInfo) { 563 printf("modifySet - failed to find RAID set \"%s\"\n", setUUIDCString); 564 exit(1); 565 } 566 567 if (autoRebuild == AUTO_YES) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetAutoRebuildKey), (void *)kCFBooleanTrue); 568 if (autoRebuild == AUTO_NO) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetAutoRebuildKey), (void *)kCFBooleanFalse); 569 if (quickRebuild == AUTO_YES) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetQuickRebuildKey), (void *)kCFBooleanTrue); 570 if (quickRebuild == AUTO_NO) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetQuickRebuildKey), (void *)kCFBooleanFalse); 571 if (blockSize) { 572 CFNumberRef blockSizeCF = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &blockSize); 573 if (blockSizeCF) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDChunkSizeKey), (void *)blockSizeCF); 574 } 575 if (hint) { 576 CFStringRef hintCF = CFStringCreateWithCString(kCFAllocatorDefault, hint, kCFStringEncodingUTF8); 577 if (hintCF) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetContentHintKey), (void *)hintCF); 578 } 579 if (timeout) { 580 CFNumberRef timeoutCF = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt64Type, &timeout); 581 if (timeoutCF) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetTimeoutKey), (void *)timeoutCF); 582 } 583 if (nickname) { 584 CFStringRef nicknameCF = CFStringCreateWithCString(kCFAllocatorDefault, nickname, kCFStringEncodingUTF8); 585 if (nicknameCF) AppleRAIDModifySet(setInfo, CFSTR(kAppleRAIDSetNameKey), (void *)nicknameCF); 586 } 587 588 printf("modifying the set \"%s\".\n", setUUIDCString); 589 AppleRAIDSetRef set = AppleRAIDUpdateSet(setInfo); 590 591 if (!set) printf("something went wrong updating the set\n"); 592 593 if (set) CFRelease(set); 594 CFRelease(setInfo); 595 CFRelease(setUUID); 596} 597 598static void 599removeMember(char * setUUIDCString, int argc, char* argv[]) 600{ 601 if (!setUUIDCString || argc < 1) { 602 usage(); 603 exit(1); 604 } 605 606 CFStringRef setUUID = CFStringCreateWithCString(kCFAllocatorDefault, setUUIDCString, kCFStringEncodingUTF8); 607 if (!setUUID) exit(1); 608 609 CFMutableDictionaryRef setInfo = AppleRAIDGetSetProperties(setUUID); 610 if (!setInfo) { 611 printf("removeMember - failed to find RAID set \"%s\"\n", setUUIDCString); 612 exit(1); 613 } 614 615 int partitionCount = argc; 616 char **firstPartition = argv; 617 618 while (argc--) { 619 printf("removing member \"%s\"\n", *argv); 620 621 CFStringRef memberUUID = CFStringCreateWithCString(kCFAllocatorDefault, *argv, kCFStringEncodingUTF8); 622 623 bool success = AppleRAIDRemoveMember(setInfo, memberUUID); 624 if (!success) { 625 printf("there was problem removing the member \"%s\"\n", *argv); 626 } 627 628 CFRelease(memberUUID); 629 argv++; 630 } 631 632 AppleRAIDSetRef set = AppleRAIDUpdateSet(setInfo); 633 634 if (!set) printf("something went wrong updating the set\n"); 635 636 if (set) CFRelease(set); 637 CFRelease(setInfo); 638 CFRelease(setUUID); 639 640 while (partitionCount--) { 641 printf("switching the partition on \"%s\" to %s.\n", *firstPartition, kRAID_OFFLINE); 642 bool success = switchPartition(*firstPartition, kRAID_OFFLINE); 643 if (!success) { 644 printf("switching the partition on \"%s\" to %s FAILED.\n", *firstPartition, kRAID_OFFLINE); 645 } 646 647 firstPartition++; 648 } 649} 650 651static void 652createLogicalVolume(char * nameCString, char * volTypeCString, int argc, char* argv[]) 653{ 654 if (!nameCString || argc) { 655 usage(); 656 exit(1); 657 } 658 659 CFStringRef lvgUUID = CFStringCreateWithCString(kCFAllocatorDefault, nameCString, kCFStringEncodingUTF8); 660 if (!lvgUUID) exit(1); 661 662 if (!volSize) volSize = 0x40000000; 663 664 CFStringRef volType = 0; 665 if (volTypeCString) { 666 volType = CFStringCreateWithCString(kCFAllocatorDefault, volTypeCString, kCFStringEncodingUTF8); 667 } else { 668 volType = CFSTR(kAppleLVMVolumeTypeConcat); 669 } 670 if (!volType) exit(1); 671 672 CFMutableDictionaryRef lvDict = AppleLVMCreateVolume(lvgUUID, volType, volSize, CFSTR(kAppleLVMVolumeLocationFast)); 673 if (!lvDict) { 674 printf("there was a problem allocating/setting up the logical volume\n"); 675 exit(1); 676 } 677 678 if (nickname) { 679 CFStringRef nameCF = CFStringCreateWithCString(kCFAllocatorDefault, nickname, kCFStringEncodingUTF8); 680 if (nameCF) AppleLVMModifyVolume(lvDict, CFSTR(kAppleLVMVolumeNameKey), (void *)nameCF); 681 } 682 683 if (hint) { 684 CFStringRef hintCF = CFStringCreateWithCString(kCFAllocatorDefault, hint, kCFStringEncodingUTF8); 685 if (hintCF) AppleLVMModifyVolume(lvDict, CFSTR(kAppleLVMVolumeContentHintKey), (void *)hintCF); 686 } 687 688 AppleLVMVolumeRef volRef = AppleLVMUpdateVolume(lvDict); 689 if (!volRef) { 690 printf("there was a problem writing out the logical volume onto the group %s.\n", nameCString); 691 exit(2); 692 } 693} 694 695static void 696destroyLogicalVolume(char * nameCString, int argc, char* argv[]) 697{ 698 if (!nameCString || argc) { 699 usage(); 700 exit(1); 701 } 702 703 CFStringRef lvUUID = CFStringCreateWithCString(kCFAllocatorDefault, nameCString, kCFStringEncodingUTF8); 704 if (!lvUUID) exit(1); 705 706 bool success = AppleLVMDestroyVolume(lvUUID); 707 if (!success) { 708 printf("there was a problem destroying the logical volume %s.\n", nameCString); 709 } 710} 711 712static void 713dumpLogicalVolumeExtents(CFMutableDictionaryRef lv) 714{ 715 CFStringRef lvUUID = CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeUUIDKey)); 716 if (!lvUUID) { printf("\ninternal error, no uuid in lv dict\n"); return; }; 717 718 CFDataRef extentData = (CFDataRef)AppleLVMGetVolumeExtents(lvUUID); 719 if (!extentData) { printf("\nno extent data found?\n"); return; }; 720 721 AppleRAIDExtentOnDisk * extentList = (AppleRAIDExtentOnDisk *)CFDataGetBytePtr(extentData); 722 UInt64 extentCount = CFDataGetLength(extentData) / sizeof(AppleRAIDExtentOnDisk); 723 if (!extentCount || !extentList) { printf("\nextent data empty?\n"); return; }; 724 725 printf("\textent list:\n"); 726 727 UInt32 i; 728 for (i = 0; i < extentCount; i++) { 729 printf(" %20llu - %12llu (%llu)\n", 730 extentList[i].extentByteOffset, 731 extentList[i].extentByteOffset + extentList[i].extentByteCount - 1, 732 extentList[i].extentByteCount); 733 } 734} 735 736static void 737dumpLogicalVolumeProperties(CFMutableDictionaryRef lv) 738{ 739 CFPrintf(CFSTR("\n%@\n"), CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeUUIDKey))); 740 CFPrintf(CFSTR("\t\"%@\" type = %@ /dev/%@\n"), 741 CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeNameKey)), 742 CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeTypeKey)), 743 CFDictionaryGetValue(lv, CFSTR("BSD Name"))); 744 CFPrintf(CFSTR("\tbyte size = %@, content hint = %@\n"), 745 CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeSizeKey)), 746 CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeContentHintKey))); 747 CFPrintf(CFSTR("\tstatus = %@, sequence = %@ extent count = %@\n"), 748 CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeStatusKey)), 749 CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeSequenceKey)), 750 CFDictionaryGetValue(lv, CFSTR(kAppleLVMVolumeExtentCountKey))); 751 CFStringRef parent = CFDictionaryGetValue(lv, CFSTR(kAppleLVMParentUUIDKey)); 752 if (parent) CFPrintf(CFSTR("\tparent = %@\n"), parent); 753 754 if (extents) dumpLogicalVolumeExtents(lv); 755 756 if (verbose) CFShow(lv); 757} 758 759static void listLogicalVolumes(char * nameCString, int argc, char* argv[]); 760 761static void 762listAllLogicalVolumes() 763{ 764 UInt32 filter = kAppleRAIDAllSets; 765 CFMutableArrayRef theList = AppleRAIDGetListOfSets(filter); 766 CFIndex setCount = theList ? CFArrayGetCount(theList) : 0; 767 768 CFIndex i; 769 for (i=0; i < setCount; i++) { 770 771 CFStringRef setName = (CFStringRef)CFArrayGetValueAtIndex(theList, i); 772 if (setName) { 773 CFMutableDictionaryRef setProp = AppleRAIDGetSetProperties(setName); 774 if (!setProp) continue; 775 776 CFStringRef level = CFDictionaryGetValue(setProp, CFSTR(kAppleRAIDLevelNameKey)); 777 if (!level) continue; 778 779 if (CFStringCompare(level, CFSTR("LVG"), kCFCompareCaseInsensitive) == kCFCompareEqualTo) { 780 781 dumpSetProperties(setProp); 782 783 char uuid[256]; 784 if (CFStringGetCString(setName, uuid, 256, kCFStringEncodingUTF8)) { 785 listLogicalVolumes(uuid, 0, NULL); 786 } 787 } 788 789 CFRelease(setProp); 790 } 791 } 792 if (theList) CFRelease(theList); 793} 794 795 796static void 797listLogicalVolumes(char * nameCString, int argc, char* argv[]) 798{ 799 if (!nameCString && !argc) { 800 listAllLogicalVolumes(); 801 exit(0); 802 } 803 804 if (!nameCString && argc == 1) nameCString = argv[0]; // hack 805 if (!nameCString) { 806 usage(); 807 exit(1); 808 } 809 810 CFStringRef lvUUID = CFStringCreateWithCString(kCFAllocatorDefault, nameCString, kCFStringEncodingUTF8); 811 if (!lvUUID) exit(1); 812 813 // try for one logical volume 814 CFMutableDictionaryRef props = AppleLVMGetVolumeProperties(lvUUID); 815 if (props) { 816 dumpLogicalVolumeProperties(props); 817 CFRelease(props); 818 return; 819 } 820 821 // go for all volumes in the group 822 CFMutableArrayRef volumes = AppleLVMGetVolumesForGroup(lvUUID, NULL); 823 if (!volumes) { 824 printf("there was a problem finding the logical volume/group %s.\n", nameCString); 825 exit(1); 826 } 827 828 int count = CFArrayGetCount(volumes); 829 if (count == 0) { 830 printf("\n%s contains no logical volumes.\n", nameCString); 831 return; 832 } 833 834 int i; 835 for (i = 0; i < count; i++) { 836 837 CFStringRef UUID = (CFStringRef)CFArrayGetValueAtIndex(volumes, i); 838 839 CFMutableDictionaryRef props = AppleLVMGetVolumeProperties(UUID); 840 if (props) { 841 dumpLogicalVolumeProperties(props); 842 CFRelease(props); 843 } 844 } 845 printf("\n"); 846} 847 848static void 849modifyLogicalVolume(char * nameCString, int argc, char* argv[]) 850{ 851 if (!nameCString || argc) { 852 usage(); 853 exit(1); 854 } 855 856 CFStringRef lvUUID = CFStringCreateWithCString(kCFAllocatorDefault, nameCString, kCFStringEncodingUTF8); 857 if (!lvUUID) exit(1); 858 859 CFMutableDictionaryRef lvDict = AppleLVMGetVolumeProperties(lvUUID); 860 if (!lvDict) { 861 printf("there was a problem finding the logical volume %s.\n", nameCString); 862 exit(1); 863 } 864 865 if (nickname) { 866 CFStringRef nameCF = CFStringCreateWithCString(kCFAllocatorDefault, nickname, kCFStringEncodingUTF8); 867 if (nameCF) AppleLVMModifyVolume(lvDict, CFSTR(kAppleLVMVolumeNameKey), (void *)nameCF); 868 } 869 870 if (hint) { 871 CFStringRef hintCF = CFStringCreateWithCString(kCFAllocatorDefault, hint, kCFStringEncodingUTF8); 872 if (hintCF) AppleLVMModifyVolume(lvDict, CFSTR(kAppleLVMVolumeContentHintKey), (void *)hintCF); 873 } 874 875 AppleLVMVolumeRef volRef = AppleLVMUpdateVolume(lvDict); 876 if (!volRef) { 877 printf("there was a problem updating the logical volume %s.\n", nameCString); 878 exit(2); 879 } 880} 881 882static void 883resizeLogicalVolume(char * nameCString, int argc, char* argv[]) 884{ 885 if (!nameCString || argc) { 886 usage(); 887 exit(1); 888 } 889 890 CFStringRef lvUUID = CFStringCreateWithCString(kCFAllocatorDefault, nameCString, kCFStringEncodingUTF8); 891 if (!lvUUID) exit(1); 892 893 CFMutableDictionaryRef lvProps = AppleLVMGetVolumeProperties(lvUUID); 894 if (!lvProps) { 895 printf("there was a problem finding the logical volume %s.\n", nameCString); 896 exit(1); 897 } 898 899 if (!volSize) { 900 CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(lvProps, CFSTR(kAppleLVMVolumeSizeKey)); 901 if (number) CFNumberGetValue(number, kCFNumberSInt64Type, &volSize); 902 volSize += 0x40000000; 903 } 904 905 UInt64 newSize = AppleLVMResizeVolume(lvProps, volSize); 906 if (!newSize) { 907 printf("there was a problem resizing the logical volume %s.\n", nameCString); 908 exit(1); 909 } 910 911 AppleLVMVolumeRef volRef = AppleLVMUpdateVolume(lvProps); 912 if (!volRef) { 913 printf("there was a problem updating the logical volume %s.\n", nameCString); 914 exit(2); 915 } 916 917 printf("the logical volume %s has been resized to 0x%lld.\n", nameCString, newSize); 918} 919 920static void 921snapshotLogicalVolume(char * nameCString, char * snapType, int argc, char* argv[]) 922{ 923 if (!nameCString || argc) { 924 usage(); 925 exit(1); 926 } 927 928 CFStringRef lvUUID = CFStringCreateWithCString(kCFAllocatorDefault, nameCString, kCFStringEncodingUTF8); 929 if (!lvUUID) exit(1); 930 931 CFMutableDictionaryRef lvProps = AppleLVMGetVolumeProperties(lvUUID); 932 if (!lvProps) { 933 printf("there was a problem finding the logical volume %s.\n", nameCString); 934 exit(1); 935 } 936 937 CFStringRef lvType = 0; 938 if (snapType) { 939 lvType = CFStringCreateWithCString(kCFAllocatorDefault, snapType, kCFStringEncodingUTF8); 940 } else { 941 lvType = CFSTR(kAppleLVMVolumeTypeSnapRO); 942 } 943 if (!lvType) exit(1); 944 945 UInt64 percent = 0; 946 if (volSize < 100) percent = volSize; 947 if (volSize <= 100) volSize = 0; 948 949 if (!volSize) { 950 CFNumberRef number = (CFNumberRef)CFDictionaryGetValue(lvProps, CFSTR(kAppleLVMVolumeSizeKey)); 951 if (number) CFNumberGetValue(number, kCFNumberSInt64Type, &volSize); 952 } 953 if (percent) volSize = volSize * percent / (UInt64)100; 954 955 // create the snap 956 CFMutableDictionaryRef snapProps = AppleLVMSnapShotVolume(lvProps, lvType, volSize); 957 if (!snapProps) { 958 printf("there was a problem initializing the snapshot for %s.\n", nameCString); 959 exit(1); 960 } 961 962 // write to disk 963 AppleLVMVolumeRef snapRef = AppleLVMUpdateVolume(snapProps); 964 if (!snapRef) { 965 printf("there was a problem updating the snapshot volume.\n"); 966 exit(2); 967 } 968 969 printf("the logical volume %s now has a snapshot.\n", nameCString); 970} 971 972static void 973callBack(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) 974{ 975 char setName[128]; 976 if (!CFStringGetCString(object, setName, 128, kCFStringEncodingUTF8)) bcopy("bogus set name?", setName, 128); 977 978 char event[128]; 979 if (!CFStringGetCString(name, event, 128, kCFStringEncodingUTF8)) bcopy("bogus event string?", event, 128); 980 981 printf("Notification for %s, event = %s.\n", setName, event); fflush(stdout); 982} 983 984static void signalHandler(int sigraised); 985 986int 987main(int argc, char* argv[]) 988{ 989 bool add = false, create = false, destroy = false, erase = false, header = false; 990 bool list = false, lvcreate = false, lvdestroy = false, lvlist = false, lvmodify = false, lvresize = false, lvsnap = false; 991 bool modify = false, remove = false, spare = false, watch = false; 992 char * setLevel = 0, * setName = 0; 993 994 /* options descriptor */ 995 static struct option longopts[] = { 996 { "add", required_argument, 0, 'a' }, 997 { "create", no_argument, 0, 'c' }, 998 { "destroy", required_argument, 0, 'd' }, 999 { "erase", no_argument, 0, 'e' }, 1000 { "header", no_argument, 0, 'h' }, 1001 { "list", no_argument, 0, 'l' }, 1002 { "modify", required_argument, 0, 'm' }, 1003 { "remove", required_argument, 0, 'r' }, 1004 { "spare", required_argument, 0, 's' }, 1005 { "watch", no_argument, 0, 'w' }, 1006 1007 { "lvcreate", required_argument, 0, 'C' }, 1008 { "lvdestroy", required_argument, 0, 'D' }, 1009 { "lvlist", no_argument, 0, 'L' }, 1010 { "lvmodify", required_argument, 0, 'M' }, 1011 { "lvresize", required_argument, 0, 'R' }, 1012 { "lvsnap", required_argument, 0, 'S' }, 1013 1014 { "auto-rebuild",required_argument, 0, 'A' }, 1015 { "block-size", required_argument, 0, 'B' }, 1016 { "extents", no_argument, 0, 'E' }, 1017 { "hint", required_argument, 0, 'H' }, 1018 { "level", required_argument, 0, 'V' }, 1019 { "name", required_argument, 0, 'N' }, 1020 { "quick-rebuild",required_argument, 0, 'Q' }, 1021 { "size", required_argument, 0, 'Z' }, 1022 { "timeout", required_argument, 0, 'T' }, 1023 1024 { "verbose", no_argument, 0, 'v' }, 1025 { "help", no_argument, 0, '?' }, 1026 { 0, 0, 0, 0 } 1027 }; 1028 1029 int ch; 1030 while ((ch = getopt_long(argc, argv, "a:cd:ehlm:r:s:wC:D:LM:R:S:A:B:EH:V:N:Q:Z:T:v?", longopts, NULL)) != -1) { 1031 1032 switch(ch) { 1033 1034 case 'a': 1035 add = true; 1036 setName = strdup(optarg); 1037 break; 1038 case 'c': 1039 create = true; 1040 break; 1041 case 'd': 1042 destroy = true; 1043 setName = strdup(optarg); 1044 break; 1045 case 'e': 1046 erase = true; 1047 break; 1048 case 'h': 1049 header = true; 1050 break; 1051 case 'l': 1052 list = true; 1053 break; 1054 case 'm': 1055 modify = true; 1056 setName = strdup(optarg); 1057 break; 1058 case 'r': 1059 remove = true; 1060 setName = strdup(optarg); 1061 break; 1062 case 's': 1063 spare = true; 1064 setName = strdup(optarg); 1065 break; 1066 case 'w': 1067 watch = true; 1068 break; 1069 1070 1071 case 'C': 1072 lvcreate = true; 1073 setName = strdup(optarg); 1074 break; 1075 case 'D': 1076 lvdestroy = true; 1077 setName = strdup(optarg); 1078 break; 1079 case 'L': 1080 lvlist = true; 1081 break; 1082 case 'M': 1083 lvmodify = true; 1084 setName = strdup(optarg); 1085 break; 1086 case 'R': 1087 lvresize = true; 1088 setName = strdup(optarg); 1089 break; 1090 case 'S': 1091 lvsnap = true; 1092 setName = strdup(optarg); 1093 break; 1094 1095 1096 case 'A': 1097 autoRebuild = ((optarg[0] == 'Y') || (optarg[0] == 'y')) ? AUTO_YES : AUTO_NO; 1098 break; 1099 case 'B': 1100 sscanf(optarg, "%lli", &blockSize); 1101 break; 1102 case 'E': 1103 extents = true; 1104 break; 1105 case 'H': 1106 hint = strdup(optarg); 1107 break; 1108 case 'V': 1109 setLevel = strdup(optarg); 1110 break; 1111 case 'N': 1112 nickname = strdup(optarg); 1113 break; 1114 case 'Q': 1115 quickRebuild = ((optarg[0] == 'Y') || (optarg[0] == 'y')) ? AUTO_YES : AUTO_NO; 1116 break; 1117 case 'Z': 1118 sscanf(optarg, "%lli", &volSize); 1119 break; 1120 case 'T': 1121 sscanf(optarg, "%lli", &timeout); 1122 break; 1123 1124 1125 case 'v': 1126 verbose = true; 1127 break; 1128 case 0: 1129 case '?': 1130 default: 1131 usage(); 1132 exit(0); 1133 } 1134 } 1135 argc -= optind; 1136 argv += optind; 1137 1138 if (!add && !create && !destroy && !erase && !header && !list && !modify && !remove && !spare && !watch && 1139 !lvcreate && !lvdestroy && !lvlist && !lvmodify && !lvresize && !lvsnap) { 1140 usage(); 1141 exit(0); 1142 } 1143 1144 if (list) { 1145 listRAIDSets(); 1146 exit(0); 1147 } 1148 1149 if (lvlist) { 1150 listLogicalVolumes(NULL, argc, argv); 1151 exit(0); 1152 } 1153 1154 if (geteuid()) { 1155 printf("ERROR: you must be super user for this operation.\n"); 1156 exit(1); 1157 } 1158 1159 if (erase) { 1160 erasePartition(argc, argv); 1161 exit(0); 1162 }; 1163 1164 if (header) { 1165 dumpHeader(argc, argv); 1166 exit(0); 1167 }; 1168 1169 if (watch) { 1170 1171 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 1172 NULL, // const void *observer 1173 callBack, 1174 CFSTR(kAppleRAIDNotificationSetDiscovered), 1175 NULL, // const void *object 1176 CFNotificationSuspensionBehaviorHold); 1177 1178 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 1179 NULL, // const void *observer 1180 callBack, 1181 CFSTR(kAppleRAIDNotificationSetTerminated), 1182 NULL, // const void *object 1183 CFNotificationSuspensionBehaviorHold); 1184 1185 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 1186 NULL, // const void *observer 1187 callBack, 1188 CFSTR(kAppleRAIDNotificationSetChanged), 1189 NULL, // const void *object 1190 CFNotificationSuspensionBehaviorHold); 1191 1192 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 1193 NULL, // const void *observer 1194 callBack, 1195 CFSTR(kAppleLVMNotificationVolumeDiscovered), 1196 NULL, // const void *object 1197 CFNotificationSuspensionBehaviorHold); 1198 1199 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 1200 NULL, // const void *observer 1201 callBack, 1202 CFSTR(kAppleLVMNotificationVolumeTerminated), 1203 NULL, // const void *object 1204 CFNotificationSuspensionBehaviorHold); 1205 1206 CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), 1207 NULL, // const void *observer 1208 callBack, 1209 CFSTR(kAppleLVMNotificationVolumeChanged), 1210 NULL, // const void *object 1211 CFNotificationSuspensionBehaviorHold); 1212 1213 // this will not fail if there is no raid controller, ie, if AppleRAID class is not instantiated in the kernel 1214 1215 AppleRAIDEnableNotifications(); 1216 } 1217 1218 1219 if (add) addMember(setName, CFSTR(kAppleRAIDMembersKey), argc, argv); 1220 if (create) createSet(setLevel, nickname, argc, argv); 1221 if (destroy) destroySet(setName, argc, argv); 1222 if (modify) modifySet(setName, argc, argv); 1223 if (remove) removeMember(setName, argc, argv); 1224 if (spare) addMember(setName, CFSTR(kAppleRAIDSparesKey), argc, argv); 1225 1226 1227 if (lvcreate) createLogicalVolume(setName, setLevel, argc, argv); 1228 if (lvdestroy) destroyLogicalVolume(setName, argc, argv); 1229 if (lvmodify) modifyLogicalVolume(setName, argc, argv); 1230 if (lvresize) resizeLogicalVolume(setName, argc, argv); 1231 if (lvsnap) snapshotLogicalVolume(setName, setLevel, argc, argv); 1232 1233 1234 if (watch) { 1235 1236 printf("watching...\n"); 1237 1238 // Set up a signal handler so we can clean up when we're interrupted from the command line 1239 // Otherwise we stay in our run loop forever. 1240 sig_t oldHandler = signal(SIGINT, signalHandler); 1241 if (oldHandler == SIG_ERR) { 1242 printf("Could not establish new signal handler"); 1243 exit(1); 1244 } 1245 1246 // Start the run loop. Now we'll receive notifications. 1247 // 1248 printf("Starting run loop.\n"); 1249 CFRunLoopRun(); 1250 1251 printf("Unexpectedly back from CFRunLoopRun()!\n"); 1252 } 1253 1254 return 0; 1255} 1256 1257static void 1258signalHandler(int sigraised) 1259{ 1260 printf("\nInterrupted.\n"); 1261 1262 AppleRAIDDisableNotifications(); 1263 1264 _exit(0); 1265} 1266