1 /* 2 libparted - a library for manipulating disk partitions 3 Copyright (C) 1999 - 2005 Free Software Foundation, Inc. 4 Copyright (C) 2007 Nikhil,Sujay,Nithin,Srivatsa. 5 6 Bug fixes and completion of the module in 2009 by Mark.Logan@sun.com. 7 8 This program is free software; you can redistribute it and/or modify 9 it under the terms of the GNU General Public License as published by 10 the Free Software Foundation; either version 2 of the License, or 11 (at your option) any later version. 12 13 This program is distributed in the hope that it will be useful, 14 but WITHOUT ANY WARRANTY; without even the implied warranty of 15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 GNU General Public License for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with this program; if not, write to the Free Software 20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 23 #include <sys/types.h> 24 #include <sys/mkdev.h> 25 #include "config.h" 26 #include "xalloc.h" 27 #include <sys/dkio.h> 28 29 /* 30 * __attribute doesn't exist on solaris 31 */ 32 #define __attribute__(X) /* nothing */ 33 34 #include <sys/vtoc.h> 35 36 #include <parted/parted.h> 37 #include <parted/debug.h> 38 #include <parted/solaris.h> 39 #include <malloc.h> 40 41 #include <ctype.h> 42 #include <errno.h> 43 #include <fcntl.h> 44 #include <libgen.h> 45 #include <stdint.h> 46 #include <stdio.h> 47 #include <stdlib.h> 48 #include <string.h> 49 50 #include <unistd.h> 51 #include <dirent.h> 52 #include <libdiskmgt.h> 53 54 #include <sys/stat.h> 55 #include <sys/types.h> 56 #include <sys/swap.h> 57 #include <sys/mnttab.h> 58 #include <sys/mntent.h> 59 60 #if ENABLE_NLS 61 #include <libintl.h> 62 #define _(String) dgettext(PACKAGE, String) 63 #else 64 #define _(String) (String) 65 #endif /* ENABLE_NLS */ 66 67 #ifndef UINT_MAX64 68 #define UINT_MAX64 0xffffffffffffffffULL 69 #endif 70 71 /* 72 * Macro to convert a device number into a partition number 73 */ 74 #define PARTITION(dev) (minor(dev) & 0x07) 75 76 77 char * 78 canonicalize_file_name(const char *name) 79 { 80 char *buf; 81 82 buf = malloc(MAXPATHLEN); 83 if (!buf) { 84 errno = ENOMEM; 85 return (NULL); 86 } 87 88 return (strcpy(buf, name)); 89 } 90 91 static int 92 _device_stat(PedDevice* dev, struct stat *dev_stat) 93 { 94 PED_ASSERT(dev != NULL, return (0)); 95 PED_ASSERT(!dev->external_mode, return (0)); 96 97 while (1) { 98 if (!stat(dev->path, dev_stat)) { 99 return (1); 100 } else { 101 if (ped_exception_throw( 102 PED_EXCEPTION_ERROR, 103 PED_EXCEPTION_RETRY_CANCEL, 104 _("Could not stat device %s - %s."), 105 dev->path, strerror(errno)) != PED_EXCEPTION_RETRY) 106 return (0); 107 } 108 } 109 } 110 111 static void 112 _device_set_length_and_sector_size(PedDevice* dev) 113 { 114 SolarisSpecific* arch_specific; 115 PedSector size; 116 struct dk_minfo dk_minfo; 117 struct dk_geom dk_geom; 118 119 PED_ASSERT(dev != NULL, return); 120 PED_ASSERT(dev->open_count > 0, return); 121 122 arch_specific = SOLARIS_SPECIFIC(dev); 123 124 dev->sector_size = PED_SECTOR_SIZE_DEFAULT; 125 dev->phys_sector_size = PED_SECTOR_SIZE_DEFAULT; 126 127 /* this ioctl requires the raw device */ 128 if (ioctl(arch_specific->fd, DKIOCGMEDIAINFO, &dk_minfo) < 0) { 129 printf("_device_get_length: ioctl DKIOCGMEDIAINFO failed\n"); 130 ped_exception_throw( 131 PED_EXCEPTION_BUG, 132 PED_EXCEPTION_CANCEL, 133 _("Unable to determine the size of %s (%s)."), 134 dev->path, 135 strerror(errno)); 136 } else { 137 size = dk_minfo.dki_capacity; 138 dev->length = size; 139 dev->sector_size = dk_minfo.dki_lbsize; 140 if (dev->sector_size != PED_SECTOR_SIZE_DEFAULT) { 141 ped_exception_throw( 142 PED_EXCEPTION_WARNING, 143 PED_EXCEPTION_OK, 144 _("Device %s has a logical sector size of " 145 "%lld. Not all parts of GNU Parted support " 146 "this at the moment, and the working code " 147 "is HIGHLY EXPERIMENTAL.\n"), 148 dev->path, dev->sector_size); 149 } 150 if (size > 0) { 151 return; 152 } 153 } 154 155 /* 156 * On some disks DKIOCGMEDIAINFO doesn't work, it returns 0, 157 * so try DKIOCG_PHYGEOM next. 158 */ 159 /* this ioctl requires the raw device */ 160 if (ioctl(arch_specific->fd, DKIOCG_PHYGEOM, &dk_geom) < 0) { 161 printf("_device_get_length: ioctl DKIOCG_PHYGEOM failed\n"); 162 ped_exception_throw( 163 PED_EXCEPTION_BUG, 164 PED_EXCEPTION_CANCEL, 165 _("Unable to determine the size of %s (%s)."), 166 dev->path, strerror(errno)); 167 168 return; 169 } 170 171 /* 172 * XXX For large disks, I am adding 16064 to the size of the disk. 173 * Solaris underreports the size of the disk, because it rounds down to 174 * a multiple of 16065. This causes a problem with Vista because Vista 175 * creates a partition that occupies the whole disk, including the 176 * blocks at the end of the disk that Solaris loses. 177 */ 178 if (dk_geom.dkg_nhead == 255 && dk_geom.dkg_nsect == 63) { 179 size = ((PedSector) dk_geom.dkg_pcyl * 180 (255 * 63)) + ((255*63)-1); 181 } else { 182 size = (PedSector) dk_geom.dkg_pcyl * 183 dk_geom.dkg_nhead * dk_geom.dkg_nsect; 184 } 185 186 dev->length = size; 187 } 188 189 static int 190 _device_probe_geometry(PedDevice* dev) 191 { 192 SolarisSpecific* arch_specific; 193 struct stat dev_stat; 194 struct dk_geom dk_geom; 195 196 PED_ASSERT(dev != NULL, return (0)); 197 PED_ASSERT(dev->open_count > 0, return (0)); 198 199 arch_specific = SOLARIS_SPECIFIC(dev); 200 201 _device_set_length_and_sector_size(dev); 202 if (dev->length == 0) { 203 printf("_device_probe_geometry: _device_get_length = 0\n"); 204 return (0); 205 } 206 207 dev->bios_geom.sectors = 63; 208 dev->bios_geom.heads = 255; 209 dev->bios_geom.cylinders = dev->length / (63 * 255); 210 if ((ioctl(arch_specific->fd, DKIOCG_PHYGEOM, &dk_geom) >= 0) && 211 dk_geom.dkg_nsect && dk_geom.dkg_nhead) { 212 dev->hw_geom.sectors = dk_geom.dkg_nsect; 213 dev->hw_geom.heads = dk_geom.dkg_nhead; 214 dev->hw_geom.cylinders = dk_geom.dkg_pcyl; 215 } else { 216 perror("_device_probe_geometry: DKIOCG_PHYGEOM"); 217 dev->hw_geom = dev->bios_geom; 218 } 219 220 return (1); 221 } 222 223 static int 224 init_ide(PedDevice *dev) 225 { 226 struct stat dev_stat; 227 228 PED_ASSERT(dev != NULL, return (0)); 229 230 if (!_device_stat(dev, &dev_stat)) { 231 printf("init_ide: _device_stat failed\n"); 232 goto error; 233 } 234 if (!ped_device_open(dev)) { 235 printf("init_ide: ped_device_open failed\n"); 236 goto error; 237 } 238 if (!_device_probe_geometry(dev)) { 239 printf("init_ide: _device_probe_geometry failed\n"); 240 goto error_close_dev; 241 } 242 243 ped_device_close(dev); 244 return (1); 245 246 error_close_dev: 247 ped_device_close(dev); 248 error: 249 return (0); 250 } 251 252 static PedDevice* 253 solaris_new(const char *path) 254 { 255 PedDevice* dev; 256 257 PED_ASSERT(path != NULL, return (NULL)); 258 259 dev = (PedDevice*) ped_malloc(sizeof (PedDevice)); 260 if (!dev) 261 goto error; 262 263 dev->path = strdup(path); 264 if (!dev->path) 265 goto error_free_dev; 266 267 dev->arch_specific 268 = (SolarisSpecific*) ped_malloc(sizeof (SolarisSpecific)); 269 if (!dev->arch_specific) 270 goto error_free_path; 271 272 dev->open_count = 0; 273 dev->read_only = 0; 274 dev->external_mode = 0; 275 dev->dirty = 0; 276 dev->boot_dirty = 0; 277 dev->model = strdup("Generic Ide"); 278 dev->type = PED_DEVICE_IDE; 279 if (!init_ide(dev)) { 280 goto error_free_arch_specific; 281 } 282 283 return (dev); 284 285 error_free_arch_specific: 286 ped_free(dev->arch_specific); 287 ped_free(dev->model); 288 error_free_path: 289 ped_free(dev->path); 290 error_free_dev: 291 ped_free(dev); 292 error: 293 return (NULL); 294 } 295 296 static void 297 solaris_destroy(PedDevice* dev) 298 { 299 PED_ASSERT(dev != NULL, return); 300 301 ped_free(dev->arch_specific); 302 ped_free(dev->model); 303 ped_free(dev->path); 304 ped_free(dev); 305 } 306 307 /* 308 * This function constructs the Solaris device name for 309 * partition num on a disk given the *p0 device for that disk. 310 * For example: partition 2 of /dev/dsk/c0d0p0 becomes /dev/dsk/c0d0p2. 311 */ 312 static char * 313 _device_get_part_path(PedDevice* dev, int num) 314 { 315 int path_len = strlen(dev->path); 316 int result_len = path_len + 16; 317 char *result; 318 319 PED_ASSERT(dev != NULL, return (NULL)); 320 PED_ASSERT(num >= 1, return (NULL)); 321 322 result = (char *)ped_malloc(result_len); 323 if (!result) 324 return (NULL); 325 326 strncpy(result, dev->path, result_len); 327 if (path_len > 10 && result[path_len - 2] == 'p' && 328 result[path_len - 1] == '0') { 329 (void) snprintf(result + path_len - 1, 330 result_len - path_len + 1, "%d", num); 331 } else { 332 (void) snprintf(result, result_len, "partition %d", num); 333 } 334 335 return (result); 336 } 337 338 static struct swaptable * 339 getswapentries(void) 340 { 341 register struct swaptable *st; 342 register struct swapent *swapent; 343 int i, num; 344 char fullpathname[MAXPATHLEN]; 345 346 /* 347 * get the number of swap entries 348 */ 349 if ((num = swapctl(SC_GETNSWP, (void *)NULL)) == -1) { 350 perror("getswapentries: swapctl SC_GETNSWP"); 351 return (NULL); 352 } 353 if (num == 0) 354 return (NULL); 355 if ((st = (swaptbl_t *)malloc(num * sizeof (swapent_t) + sizeof (int))) 356 == NULL) { 357 printf("getswapentries: malloc 1 failed.\n"); 358 return (NULL); 359 } 360 swapent = st->swt_ent; 361 for (i = 0; i < num; i++, swapent++) { 362 if ((swapent->ste_path = malloc(MAXPATHLEN)) == NULL) { 363 printf("getswapentries: malloc 2 failed.\n"); 364 goto error; 365 } 366 } 367 st->swt_n = num; 368 if ((num = swapctl(SC_LIST, (void *)st)) == -1) { 369 perror("getswapentries: swapctl SC_LIST"); 370 goto error; 371 } 372 swapent = st->swt_ent; 373 for (i = 0; i < num; i++, swapent++) { 374 if (*swapent->ste_path != '/') { 375 printf("getswapentries: %s\n", swapent->ste_path); 376 (void) snprintf(fullpathname, sizeof (fullpathname), 377 "/dev/%s", swapent->ste_path); 378 (void) strcpy(swapent->ste_path, fullpathname); 379 } 380 } 381 382 return (st); 383 384 error: 385 free(st); 386 return (NULL); 387 } 388 389 static void 390 freeswapentries(st) 391 struct swaptable *st; 392 { 393 register struct swapent *swapent; 394 int i; 395 396 swapent = st->swt_ent; 397 for (i = 0; i < st->swt_n; i++, swapent++) 398 free(swapent->ste_path); 399 free(st); 400 } 401 402 /* 403 * function getpartition: 404 */ 405 static int 406 getpartition(PedDevice* dev, char *pathname) 407 { 408 SolarisSpecific* arch_specific; 409 int mfd; 410 struct dk_cinfo dkinfo; 411 struct dk_cinfo cur_disk_dkinfo; 412 struct stat stbuf; 413 char raw_device[MAXPATHLEN]; 414 int found = -1; 415 416 PED_ASSERT(dev != NULL, return (found)); 417 PED_ASSERT(pathname != NULL, return (found)); 418 419 arch_specific = SOLARIS_SPECIFIC(dev); 420 421 /* 422 * Map the block device name to the raw device name. 423 * If it doesn't appear to be a device name, skip it. 424 */ 425 if (strncmp(pathname, "/dev/", 5)) 426 return (found); 427 (void) strcpy(raw_device, "/dev/r"); 428 (void) strcat(raw_device, pathname + strlen("/dev/")); 429 /* 430 * Determine if this appears to be a disk device. 431 * First attempt to open the device. If if fails, skip it. 432 */ 433 if ((mfd = open(raw_device, O_RDWR | O_NDELAY)) < 0) { 434 return (found); 435 } 436 if (fstat(mfd, &stbuf) == -1) { 437 perror("getpartition: fstat raw_device"); 438 (void) close(mfd); 439 return (found); 440 } 441 /* 442 * Must be a character device 443 */ 444 if (!S_ISCHR(stbuf.st_mode)) { 445 printf("getpartition: not character device\n"); 446 (void) close(mfd); 447 return (found); 448 } 449 /* 450 * Attempt to read the configuration info on the disk. 451 */ 452 if (ioctl(mfd, DKIOCINFO, &dkinfo) < 0) { 453 perror("getpartition: ioctl DKIOCINFO raw_device"); 454 (void) close(mfd); 455 return (found); 456 } 457 /* 458 * Finished with the opened device 459 */ 460 (void) close(mfd); 461 462 /* 463 * Now get the info about the current disk 464 */ 465 if (ioctl(arch_specific->fd, DKIOCINFO, &cur_disk_dkinfo) < 0) { 466 (void) close(mfd); 467 return (found); 468 } 469 470 /* 471 * If it's not the disk we're interested in, it doesn't apply. 472 */ 473 if (cur_disk_dkinfo.dki_ctype != dkinfo.dki_ctype || 474 cur_disk_dkinfo.dki_cnum != dkinfo.dki_cnum || 475 cur_disk_dkinfo.dki_unit != dkinfo.dki_unit || 476 strcmp(cur_disk_dkinfo.dki_dname, dkinfo.dki_dname) != 0) { 477 return (found); 478 } 479 480 /* 481 * Extract the partition that is mounted. 482 */ 483 return (PARTITION(stbuf.st_rdev)); 484 } 485 486 /* 487 * This Routine checks to see if there are partitions used for swapping overlaps 488 * a given portion of a disk. If the start parameter is < 0, it means 489 * that the entire disk should be checked 490 */ 491 static int 492 checkswap(PedDevice* dev, diskaddr_t start, diskaddr_t end) 493 { 494 SolarisSpecific* arch_specific; 495 struct extvtoc extvtoc; 496 struct swaptable *st; 497 struct swapent *swapent; 498 int i; 499 int found = 0; 500 int part; 501 diskaddr_t p_start; 502 diskaddr_t p_size; 503 504 PED_ASSERT(dev != NULL, return (0)); 505 506 arch_specific = SOLARIS_SPECIFIC(dev); 507 508 if (ioctl(arch_specific->fd, DKIOCGEXTVTOC, &extvtoc) == -1) { 509 return (0); 510 } 511 512 /* 513 * check for swap entries 514 */ 515 st = getswapentries(); 516 /* 517 * if there are no swap entries return. 518 */ 519 if (st == (struct swaptable *)NULL) 520 return (0); 521 swapent = st->swt_ent; 522 for (i = 0; i < st->swt_n; i++, swapent++) { 523 if ((part = getpartition(dev, swapent->ste_path)) != -1) { 524 if (start == UINT_MAX64) { 525 found = -1; 526 break; 527 } 528 p_start = extvtoc.v_part[part].p_start; 529 p_size = extvtoc.v_part[part].p_size; 530 if (start >= p_start + p_size || end < p_start) { 531 continue; 532 } 533 found = -1; 534 break; 535 } 536 } 537 freeswapentries(st); 538 539 return (found); 540 } 541 542 /* 543 * Determines if there are partitions that are a part of an SVM, VxVM, zpool 544 * volume or a live upgrade device, overlapping a given portion of a disk. 545 * Mounts and swap devices are checked in legacy format code. 546 */ 547 static int 548 checkdevinuse(PedDevice *dev, diskaddr_t start, diskaddr_t end, int print) 549 { 550 int error; 551 int found = 0; 552 int check = 0; 553 int i; 554 int part = 0; 555 uint64_t slice_start, slice_size; 556 dm_descriptor_t *slices = NULL; 557 nvlist_t *attrs = NULL; 558 char *usage; 559 char *name; 560 char cur_disk_path[MAXPATHLEN]; 561 char *pcur_disk_path; 562 563 PED_ASSERT(dev != NULL, return (found)); 564 565 /* 566 * Truncate the characters following "d*", such as "s*" or "p*" 567 */ 568 strcpy(cur_disk_path, dev->path); 569 pcur_disk_path = basename(cur_disk_path); 570 name = strrchr(pcur_disk_path, 'd'); 571 if (name) { 572 name++; 573 for (; (*name <= '9') && (*name >= '0'); name++) 574 ; 575 *name = (char)0; 576 } 577 578 /* 579 * For format, we get basic 'in use' details from libdiskmgt. After 580 * that we must do the appropriate checking to see if the 'in use' 581 * details require a bit of additional work. 582 */ 583 584 dm_get_slices(pcur_disk_path, &slices, &error); 585 if (error) { 586 /* 587 * If ENODEV, it actually means the device is not in use. 588 * We will return (0) without displaying error. 589 */ 590 if (error != ENODEV) { 591 printf("checkdevinuse: Error1 occurred with device in " 592 "use checking: %s\n", strerror(error)); 593 return (found); 594 } 595 } 596 if (slices == NULL) 597 return (found); 598 599 for (i = 0; slices[i] != NULL; i++) { 600 /* 601 * If we are checking the whole disk 602 * then any and all in use data is 603 * relevant. 604 */ 605 if (start == UINT_MAX64) { 606 name = dm_get_name(slices[i], &error); 607 if (error != 0 || !name) { 608 printf("checkdevinuse: Error2 occurred with " 609 "device in use checking: %s\n", 610 strerror(error)); 611 continue; 612 } 613 printf("checkdevinuse: name1 %s\n", name); 614 if (dm_inuse(name, &usage, DM_WHO_FORMAT, &error) || 615 error) { 616 if (error != 0) { 617 dm_free_name(name); 618 name = NULL; 619 printf("checkdevinuse: Error3 " 620 "occurred with device " 621 "in use checking: %s\n", 622 strerror(error)); 623 continue; 624 } 625 dm_free_name(name); 626 name = NULL; 627 /* 628 * If this is a dump device, then it is 629 * a failure. You cannot format a slice 630 * that is a dedicated dump device. 631 */ 632 633 if (strstr(usage, DM_USE_DUMP)) { 634 if (print) { 635 printf(usage); 636 free(usage); 637 } 638 dm_free_descriptors(slices); 639 return (1); 640 } 641 /* 642 * We really found a device that is in use. 643 * Set 'found' for the return value. 644 */ 645 found ++; 646 check = 1; 647 if (print) { 648 printf(usage); 649 free(usage); 650 } 651 } 652 } else { 653 /* 654 * Before getting the in use data, verify that the 655 * current slice is within the range we are checking. 656 */ 657 attrs = dm_get_attributes(slices[i], &error); 658 if (error) { 659 printf("checkdevinuse: Error4 occurred with " 660 "device in use checking: %s\n", 661 strerror(error)); 662 continue; 663 } 664 if (attrs == NULL) { 665 continue; 666 } 667 668 (void) nvlist_lookup_uint64(attrs, DM_START, 669 &slice_start); 670 (void) nvlist_lookup_uint64(attrs, DM_SIZE, 671 &slice_size); 672 if (start >= (slice_start + slice_size) || 673 (end < slice_start)) { 674 nvlist_free(attrs); 675 attrs = NULL; 676 continue; 677 } 678 name = dm_get_name(slices[i], &error); 679 if (error != 0 || !name) { 680 printf("checkdevinuse: Error5 occurred with " 681 "device in use checking: %s\n", 682 strerror(error)); 683 nvlist_free(attrs); 684 attrs = NULL; 685 continue; 686 } 687 if (dm_inuse(name, &usage, 688 DM_WHO_FORMAT, &error) || error) { 689 if (error != 0) { 690 dm_free_name(name); 691 name = NULL; 692 printf("checkdevinuse: Error6 " 693 "occurred with device " 694 "in use checking: %s\n", 695 strerror(error)); 696 nvlist_free(attrs); 697 attrs = NULL; 698 continue; 699 } 700 dm_free_name(name); 701 name = NULL; 702 /* 703 * If this is a dump device, then it is 704 * a failure. You cannot format a slice 705 * that is a dedicated dump device. 706 */ 707 if (strstr(usage, DM_USE_DUMP)) { 708 if (print) { 709 printf(usage); 710 free(usage); 711 } 712 dm_free_descriptors(slices); 713 nvlist_free(attrs); 714 return (1); 715 } 716 /* 717 * We really found a device that is in use. 718 * Set 'found' for the return value. 719 */ 720 found ++; 721 check = 1; 722 if (print) { 723 printf(usage); 724 free(usage); 725 } 726 } 727 } 728 /* 729 * If check is set it means we found a slice(the current slice) 730 * on this device in use in some way. We potentially want 731 * to check this slice when labeling is requested. 732 */ 733 if (check) { 734 name = dm_get_name(slices[i], &error); 735 if (error != 0 || !name) { 736 printf("checkdevinuse: Error7 occurred with " 737 "device in use checking: %s\n", 738 strerror(error)); 739 nvlist_free(attrs); 740 attrs = NULL; 741 continue; 742 } 743 part = getpartition(dev, name); 744 dm_free_name(name); 745 name = NULL; 746 check = 0; 747 } 748 /* 749 * If we have attributes then we have successfully 750 * found the slice we were looking for and we also 751 * know this means we are not searching the whole 752 * disk so break out of the loop 753 * now. 754 */ 755 if (attrs) { 756 nvlist_free(attrs); 757 break; 758 } 759 } 760 761 if (slices) { 762 dm_free_descriptors(slices); 763 } 764 765 return (found); 766 } 767 768 /* 769 * This routine checks to see if there are mounted partitions overlapping 770 * a given portion of a disk. If the start parameter is < 0, it means 771 * that the entire disk should be checked. 772 */ 773 static int 774 checkmount(PedDevice* dev, diskaddr_t start, diskaddr_t end) 775 { 776 SolarisSpecific* arch_specific; 777 struct extvtoc extvtoc; 778 diskaddr_t p_start; 779 diskaddr_t p_size; 780 FILE *fp; 781 int found = 0; 782 int part; 783 struct mnttab mnt_record; 784 struct mnttab *mp = &mnt_record; 785 786 PED_ASSERT(dev != NULL, return (found)); 787 788 arch_specific = SOLARIS_SPECIFIC(dev); 789 790 if (ioctl(arch_specific->fd, DKIOCGEXTVTOC, &extvtoc) == -1) { 791 return (0); 792 } 793 794 /* 795 * Open the mount table. 796 */ 797 fp = fopen(MNTTAB, "r"); 798 if (fp == NULL) { 799 printf("checkmount: Unable to open mount table.\n"); 800 return (0); 801 } 802 /* 803 * Loop through the mount table until we run out of entries. 804 */ 805 while ((getmntent(fp, mp)) != -1) { 806 807 if ((part = getpartition(dev, mp->mnt_special)) == -1) 808 continue; 809 810 /* 811 * It's a mount on the disk we're checking. If we are 812 * checking whole disk, then we found trouble. We can 813 * quit searching. 814 */ 815 if (start == UINT_MAX64) { 816 found = -1; 817 break; 818 } 819 820 /* 821 * If the partition overlaps the zone we're checking, 822 * then we found trouble. We can quit searching. 823 */ 824 p_start = extvtoc.v_part[part].p_start; 825 p_size = extvtoc.v_part[part].p_size; 826 if (start >= p_start + p_size || end < p_start) { 827 continue; 828 } 829 found = -1; 830 break; 831 } 832 /* 833 * Close down the mount table. 834 */ 835 (void) fclose(fp); 836 837 return (found); 838 } 839 840 /* 841 * Return 1 if the device is busy, 0 otherwise. 842 */ 843 static int 844 solaris_is_busy(PedDevice* dev) 845 { 846 PED_ASSERT(dev != NULL, return (0)); 847 PED_ASSERT(dev->open_count > 0, return (0)); 848 849 if (checkmount(dev, (diskaddr_t)-1, (diskaddr_t)-1)) 850 return (1); 851 852 if (checkswap(dev, (diskaddr_t)-1, (diskaddr_t)-1)) 853 return (1); 854 855 if (checkdevinuse(dev, (diskaddr_t)-1, (diskaddr_t)-1, 1)) 856 return (1); 857 858 return (0); 859 } 860 861 /* 862 * This will accept a dev->path that looks like this: 863 * /devices/pci@0,0/pci-ide@1f,2/ide@0/cmdk@0,0:q 864 * /devices/pci@0,0/pci-ide@1f,2/ide@0/cmdk@0,0:q,raw 865 * or this: 866 * /dev/dsk/c0d0p0 867 * /dev/rdsk/c0d0p0 868 * It has to open the raw device, so it converts to it locally, if necessary. 869 */ 870 static int 871 solaris_open(PedDevice* dev) 872 { 873 SolarisSpecific* arch_specific; 874 char rawname[MAXPATHLEN]; 875 876 PED_ASSERT(dev != NULL, return (0)); 877 878 arch_specific = SOLARIS_SPECIFIC(dev); 879 880 /* 881 * Convert to the raw device, unless it already is. 882 */ 883 if (strncmp(dev->path, "/devices", 8) == 0) { 884 if (strncmp(&dev->path[strlen(dev->path)-4], ",raw", 4)) { 885 snprintf(rawname, sizeof (rawname), "%s,raw", 886 dev->path); 887 } else { 888 strcpy(rawname, dev->path); 889 } 890 } else { 891 /* 892 * Assumes it is of the form: /dev/dsk/ or /dev/rdsk/ 893 */ 894 if (strncmp(dev->path, "/dev/dsk/", 9) == 0) { 895 snprintf(rawname, sizeof (rawname), "/dev/rdsk/%s", 896 &dev->path[9]); 897 } else { 898 strcpy(rawname, dev->path); 899 } 900 } 901 902 retry: 903 arch_specific->fd = open(rawname, O_RDWR); 904 905 if (arch_specific->fd == -1) { 906 char *rw_error_msg = strerror(errno); 907 908 arch_specific->fd = open(rawname, O_RDONLY); 909 910 if (arch_specific->fd == -1) { 911 printf("solaris_open: open(\"%s\") failed\n", rawname); 912 if (ped_exception_throw( 913 PED_EXCEPTION_ERROR, 914 PED_EXCEPTION_RETRY_CANCEL, 915 _("Error opening %s: %s"), 916 rawname, strerror(errno)) != PED_EXCEPTION_RETRY) { 917 return (0); 918 } else { 919 goto retry; 920 } 921 } else { 922 ped_exception_throw( 923 PED_EXCEPTION_WARNING, 924 PED_EXCEPTION_OK, 925 _("Unable to open %s read-write (%s). %s has " 926 "been opened read-only."), 927 rawname, rw_error_msg, rawname); 928 dev->read_only = 1; 929 } 930 } else { 931 dev->read_only = 0; 932 } 933 934 return (1); 935 } 936 937 static int 938 solaris_refresh_open(PedDevice* dev) 939 { 940 return (1); 941 } 942 943 static int 944 solaris_close(PedDevice* dev) 945 { 946 SolarisSpecific* arch_specific; 947 948 PED_ASSERT(dev != NULL, return (0)); 949 950 arch_specific = SOLARIS_SPECIFIC(dev); 951 952 close(arch_specific->fd); 953 return (1); 954 } 955 956 static int 957 _do_fsync(PedDevice* dev) 958 { 959 SolarisSpecific* arch_specific; 960 int status; 961 PedExceptionOption ex_status; 962 963 PED_ASSERT(dev != NULL, return (0)); 964 PED_ASSERT(dev->open_count > 0, return (0)); 965 966 arch_specific = SOLARIS_SPECIFIC(dev); 967 968 while (1) { 969 status = fsync(arch_specific->fd); 970 if (status >= 0) 971 break; 972 973 ex_status = ped_exception_throw( 974 PED_EXCEPTION_ERROR, 975 PED_EXCEPTION_RETRY_IGNORE_CANCEL, 976 _("%s during fsync on %s"), 977 strerror(errno), dev->path); 978 979 switch (ex_status) { 980 case PED_EXCEPTION_IGNORE: 981 return (1); 982 983 case PED_EXCEPTION_RETRY: 984 break; 985 986 case PED_EXCEPTION_UNHANDLED: 987 ped_exception_catch(); 988 case PED_EXCEPTION_CANCEL: 989 return (0); 990 } 991 } 992 return (1); 993 } 994 995 static int 996 solaris_refresh_close(PedDevice* dev) 997 { 998 if (dev->dirty) 999 _do_fsync(dev); 1000 return (1); 1001 } 1002 1003 static int 1004 _device_seek(const PedDevice* dev, PedSector sector) 1005 { 1006 SolarisSpecific* arch_specific; 1007 1008 PED_ASSERT(dev != NULL, return (0)); 1009 PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return (0)); 1010 PED_ASSERT(dev->open_count > 0, return (0)); 1011 PED_ASSERT(!dev->external_mode, return (0)); 1012 1013 arch_specific = SOLARIS_SPECIFIC(dev); 1014 1015 if (sizeof (off_t) < 8) { 1016 off64_t pos = (off64_t)(sector * dev->sector_size); 1017 return (lseek64(arch_specific->fd, pos, SEEK_SET) == pos); 1018 } else { 1019 off_t pos = sector * dev->sector_size; 1020 return (lseek(arch_specific->fd, pos, SEEK_SET) == pos); 1021 } 1022 } 1023 1024 static int 1025 solaris_read(const PedDevice* dev, void* vbuffer, PedSector start, 1026 PedSector count) 1027 { 1028 SolarisSpecific* arch_specific; 1029 int status; 1030 PedExceptionOption ex_status; 1031 size_t read_length = count * dev->sector_size; 1032 void *diobuf; 1033 char *buffer = vbuffer; 1034 1035 PED_ASSERT(dev != NULL, return (0)); 1036 PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return (0)); 1037 PED_ASSERT(dev->open_count > 0, return (0)); 1038 PED_ASSERT(!dev->external_mode, return (0)); 1039 1040 arch_specific = SOLARIS_SPECIFIC(dev); 1041 1042 while (1) { 1043 if (_device_seek(dev, start)) 1044 break; 1045 1046 ex_status = ped_exception_throw( 1047 PED_EXCEPTION_ERROR, 1048 PED_EXCEPTION_RETRY_IGNORE_CANCEL, 1049 _("%s during seek for read on %s"), 1050 strerror(errno), dev->path); 1051 1052 switch (ex_status) { 1053 case PED_EXCEPTION_IGNORE: 1054 return (1); 1055 1056 case PED_EXCEPTION_RETRY: 1057 break; 1058 1059 case PED_EXCEPTION_UNHANDLED: 1060 ped_exception_catch(); 1061 case PED_EXCEPTION_CANCEL: 1062 return (0); 1063 } 1064 } 1065 1066 diobuf = memalign(dev->sector_size, read_length); 1067 if (diobuf == NULL) { 1068 printf("solaris_read: cannot memalign %u\n", read_length); 1069 return (0); 1070 } 1071 1072 while (1) { 1073 status = read(arch_specific->fd, diobuf, read_length); 1074 1075 if (status > 0) 1076 memcpy(buffer, diobuf, status); 1077 1078 if (status == read_length) 1079 break; 1080 1081 if (status > 0) { 1082 printf("solaris_read: partial read %d of %d\n", 1083 status, read_length); 1084 read_length -= status; 1085 buffer += status; 1086 continue; 1087 } 1088 1089 ex_status = ped_exception_throw( 1090 PED_EXCEPTION_ERROR, 1091 PED_EXCEPTION_RETRY_IGNORE_CANCEL, 1092 _("%s during read on %s"), 1093 strerror(errno), 1094 dev->path); 1095 1096 switch (ex_status) { 1097 case PED_EXCEPTION_IGNORE: 1098 free(diobuf); 1099 return (1); 1100 1101 case PED_EXCEPTION_RETRY: 1102 break; 1103 1104 case PED_EXCEPTION_UNHANDLED: 1105 ped_exception_catch(); 1106 case PED_EXCEPTION_CANCEL: 1107 free(diobuf); 1108 return (0); 1109 } 1110 } 1111 1112 free(diobuf); 1113 1114 return (1); 1115 } 1116 1117 static int 1118 solaris_write(PedDevice* dev, const void* buffer, PedSector start, 1119 PedSector count) 1120 { 1121 SolarisSpecific* arch_specific; 1122 int status; 1123 PedExceptionOption ex_status; 1124 size_t write_length = count * dev->sector_size; 1125 char *diobuf; 1126 char *diobuf_start; 1127 1128 PED_ASSERT(dev != NULL, return (0)); 1129 PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, return (0)); 1130 PED_ASSERT(dev->open_count > 0, return (0)); 1131 PED_ASSERT(!dev->external_mode, return (0)); 1132 1133 arch_specific = SOLARIS_SPECIFIC(dev); 1134 1135 if (dev->read_only) { 1136 if (ped_exception_throw( 1137 PED_EXCEPTION_ERROR, 1138 PED_EXCEPTION_IGNORE_CANCEL, 1139 _("Can't write to %s, because it is opened read-only."), 1140 dev->path) != PED_EXCEPTION_IGNORE) 1141 return (0); 1142 else 1143 return (1); 1144 } 1145 1146 while (1) { 1147 if (_device_seek(dev, start)) 1148 break; 1149 1150 ex_status = ped_exception_throw( 1151 PED_EXCEPTION_ERROR, PED_EXCEPTION_RETRY_IGNORE_CANCEL, 1152 _("%s during seek for write on %s"), 1153 strerror(errno), dev->path); 1154 1155 switch (ex_status) { 1156 case PED_EXCEPTION_IGNORE: 1157 return (1); 1158 1159 case PED_EXCEPTION_RETRY: 1160 break; 1161 1162 case PED_EXCEPTION_UNHANDLED: 1163 ped_exception_catch(); 1164 case PED_EXCEPTION_CANCEL: 1165 return (0); 1166 } 1167 } 1168 1169 #ifdef READ_ONLY 1170 printf("solaris_write(\"%s\", %p, %d, %d)\n", 1171 dev->path, buffer, (int)start, (int)count); 1172 #else 1173 dev->dirty = 1; 1174 1175 diobuf = memalign((size_t)PED_SECTOR_SIZE_DEFAULT, write_length); 1176 if (diobuf == NULL) { 1177 printf("solaris_write: cannot memalign %u\n", write_length); 1178 return (0); 1179 } 1180 1181 memcpy(diobuf, buffer, write_length); 1182 diobuf_start = diobuf; 1183 while (1) { 1184 status = write(arch_specific->fd, diobuf, write_length); 1185 if (status == write_length) 1186 break; 1187 if (status > 0) { 1188 printf("solaris_write: partial write %d of %d\n", 1189 status, write_length); 1190 write_length -= status; 1191 diobuf += status; 1192 continue; 1193 } 1194 1195 ex_status = ped_exception_throw( 1196 PED_EXCEPTION_ERROR, 1197 PED_EXCEPTION_RETRY_IGNORE_CANCEL, 1198 _("%s during write on %s"), 1199 strerror(errno), dev->path); 1200 1201 switch (ex_status) { 1202 case PED_EXCEPTION_IGNORE: 1203 free(diobuf_start); 1204 return (1); 1205 1206 case PED_EXCEPTION_RETRY: 1207 break; 1208 1209 case PED_EXCEPTION_UNHANDLED: 1210 ped_exception_catch(); 1211 case PED_EXCEPTION_CANCEL: 1212 free(diobuf_start); 1213 return (0); 1214 } 1215 } 1216 free(diobuf_start); 1217 #endif /* !READ_ONLY */ 1218 1219 return (1); 1220 } 1221 1222 1223 /* 1224 * returns the number of sectors that are ok. 1225 * This is never called. It would get called through ped_device_check(). 1226 */ 1227 static PedSector 1228 solaris_check(PedDevice* dev, void* buffer, PedSector start, PedSector count) 1229 { 1230 SolarisSpecific* arch_specific; 1231 PedSector done; 1232 int status; 1233 void* diobuf; 1234 1235 PED_ASSERT(dev != NULL, return (0LL)); 1236 PED_ASSERT(dev->sector_size % PED_SECTOR_SIZE_DEFAULT == 0, 1237 return (0LL)); 1238 PED_ASSERT(dev->open_count > 0, return (0LL)); 1239 PED_ASSERT(!dev->external_mode, return (0LL)); 1240 1241 printf("solaris_check: start %lld count %lld\n", start, count); 1242 1243 arch_specific = SOLARIS_SPECIFIC(dev); 1244 1245 if (!_device_seek(dev, start)) 1246 return (0LL); 1247 1248 diobuf = memalign(PED_SECTOR_SIZE_DEFAULT, count * dev->sector_size); 1249 if (diobuf == NULL) { 1250 printf("solaris_check: cannot memalign %u\n", 1251 count * dev->sector_size); 1252 return (0LL); 1253 } 1254 1255 for (done = 0; done < count; done += status / dev->sector_size) { 1256 status = read(arch_specific->fd, diobuf, 1257 (size_t)((count - done) * dev->sector_size)); 1258 if (status < 0) 1259 break; 1260 } 1261 free(diobuf); 1262 1263 return (done); 1264 } 1265 1266 static int 1267 solaris_sync(PedDevice* dev) 1268 { 1269 PED_ASSERT(dev != NULL, return (0)); 1270 PED_ASSERT(!dev->external_mode, return (0)); 1271 1272 if (dev->read_only) 1273 return (1); 1274 if (!_do_fsync(dev)) 1275 return (0); 1276 return (1); 1277 } 1278 1279 /* 1280 * Returns all *p0 block devices. 1281 * open the raw device so ioctl works. 1282 */ 1283 static void 1284 solaris_probe_all() 1285 { 1286 DIR *dir; 1287 struct dirent *dp; 1288 char *pname; 1289 char block_path[256]; 1290 char raw_path[256]; 1291 struct stat buffer; 1292 int fd; 1293 1294 dir = opendir("/dev/dsk"); 1295 while ((dp = readdir(dir)) != NULL) { 1296 1297 pname = dp->d_name + strlen(dp->d_name) - 2; 1298 if (strcmp(pname, "p0") == 0) { 1299 1300 strncpy(block_path, "/dev/dsk/", sizeof (block_path)); 1301 strncat(block_path, dp->d_name, sizeof (block_path)); 1302 1303 strncpy(raw_path, "/dev/rdsk/", sizeof (raw_path)); 1304 strncat(raw_path, dp->d_name, sizeof (raw_path)); 1305 1306 if (stat(block_path, &buffer) == 0) { 1307 1308 if ((fd = open(raw_path, O_RDONLY)) < 0) { 1309 continue; 1310 } 1311 1312 #ifdef DONT_ALLOW_REMOVEABLE_DEVICES 1313 int n = 0; 1314 if (ioctl(fd, DKIOCREMOVABLE, &n) < 0) { 1315 char msg[MAXPATHLEN]; 1316 snprintf(msg, sizeof (msg), 1317 "ioctl(\"%s\", DKIOCREMOVABLE)", 1318 raw_path); 1319 perror(msg); 1320 } else if (!n) { 1321 /* 1322 * Not a removable device 1323 * printf("solaris_probe_all: %s\n", 1324 * block_path); 1325 */ 1326 } 1327 #endif /* DONT_ALLOW_REMOVEABLE_DEVICES */ 1328 1329 _ped_device_probe(block_path); 1330 close(fd); 1331 } 1332 } 1333 } 1334 } 1335 1336 static char * 1337 solaris_partition_get_path(const PedPartition* part) 1338 { 1339 return (_device_get_part_path(part->disk->dev, part->num)); 1340 } 1341 1342 /* 1343 * Returns 1 if the partition is busy in some way, 0 otherwise. 1344 */ 1345 static int 1346 solaris_partition_is_busy(const PedPartition* part) 1347 { 1348 int r1, r2, r3; 1349 1350 PED_ASSERT(part != NULL, return (0)); 1351 1352 r1 = checkmount(part->geom.dev, part->geom.start, part->geom.end); 1353 r2 = checkswap(part->geom.dev, part->geom.start, part->geom.end); 1354 r3 = checkdevinuse(part->geom.dev, part->geom.start, part->geom.end, 1); 1355 1356 if (r1 || r2 || r3) 1357 return (1); 1358 1359 return (0); 1360 } 1361 1362 static int 1363 solaris_disk_commit(PedDisk* disk) 1364 { 1365 return (1); 1366 } 1367 1368 static PedDeviceArchOps solaris_dev_ops = { 1369 ._new = solaris_new, 1370 .destroy = solaris_destroy, 1371 .is_busy = solaris_is_busy, 1372 .open = solaris_open, 1373 .refresh_open = solaris_refresh_open, 1374 .close = solaris_close, 1375 .refresh_close = solaris_refresh_close, 1376 .read = solaris_read, 1377 .write = solaris_write, 1378 .check = solaris_check, 1379 .sync = solaris_sync, 1380 .sync_fast = solaris_sync, 1381 .probe_all = solaris_probe_all 1382 }; 1383 1384 PedDiskArchOps solaris_disk_ops = { 1385 .partition_get_path = solaris_partition_get_path, 1386 .partition_is_busy = solaris_partition_is_busy, 1387 .disk_commit = solaris_disk_commit 1388 }; 1389 1390 PedArchitecture ped_solaris_arch = { 1391 .dev_ops = &solaris_dev_ops, 1392 .disk_ops = &solaris_disk_ops 1393 };