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 };