4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
21 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
22 /* All Rights Reserved */
25 /* Copyright (c) 1984 AT&T */
26 /* All Rights Reserved */
30 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
31 * Use is subject to license terms.
35 * Print a disk partition map (volume table of contents, or VTOC).
46 #include <sys/types.h>
50 #include <sys/mnttab.h>
51 #include <sys/vfstab.h>
52 #include <sys/mkdev.h>
54 #include <sys/efi_partition.h>
56 * Assumes V_NUMPAR must be a power of 2.
58 * for V_NUMPAR = 8, we have
59 * parttn(x)=(x & 0x07) noparttn(x)=(x & 0x3fff8)
61 * for V_NUMPAR = 16, we have
62 * parttn(x)=(x & 0x0f) noparttn(x)=(x & 0x3fff0)
64 #define parttn(x) (x % V_NUMPAR)
65 #define noparttn(x) (x & (MAXMIN & ~(V_NUMPAR-1)))
68 * Disk freespace structure.
71 u_longlong_t fr_start
; /* Start of free space */
72 u_longlong_t fr_size
; /* Length of free space */
75 static freemap_t
*findfree(struct dk_geom
*, struct extvtoc
*);
76 static int partcmp(const void *, const void *);
77 static int partcmp64(const void *, const void *);
78 static int prtvtoc(char *);
79 static void putfree(struct extvtoc
*, freemap_t
*);
80 static void putfree64(struct dk_gpt
*, freemap_t
*);
81 static void puttable(struct dk_geom
*, struct extvtoc
*, freemap_t
*,
83 static void puttable64(struct dk_gpt
*, freemap_t
*,
85 static int readgeom(int, char *, struct dk_geom
*);
86 static int readvtoc(int, char *, struct extvtoc
*);
87 static int readefi(int, char *, struct dk_gpt
**);
88 static void usage(void);
89 static int warn(char *, char *);
90 static char *safe_strdup(char *);
95 extern char *getfullrawname();
99 static short fflag
; /* Print freespace shell assignments */
100 static short hflag
; /* Omit headers */
101 static short sflag
; /* Omit all but the column header */
102 static char *fstab
= VFSTAB
; /* Fstab pathname */
103 static char *mnttab
= MNTTAB
; /* mnttab pathname */
104 static char *progname
; /* Last qualifier of arg0 */
107 main(int ac
, char **av
)
111 if (progname
= strrchr(av
[0], '/'))
115 while ((idx
= getopt(ac
, av
, "fhst:m:")) != -1)
139 idx
|= prtvtoc(av
[optind
++]);
140 return (idx
== 0 ? 0 : 1);
143 static freemap_t
*freemap
;
145 * findfree(): Find free space on a disk.
148 findfree(struct dk_geom
*geom
, struct extvtoc
*vtoc
)
150 struct extpartition
*part
;
151 struct extpartition
**list
;
155 struct extpartition
*sorted
[V_NUMPAR
+ 1];
157 freemap
= calloc(sizeof (freemap_t
), V_NUMPAR
+ 1);
158 cylsize
= (geom
->dkg_nsect
) * (geom
->dkg_nhead
);
159 fullsize
= (diskaddr_t
)(geom
->dkg_ncyl
) * cylsize
;
160 if (vtoc
->v_nparts
> V_NUMPAR
) {
161 (void) warn("putfree()", "Too many partitions on disk!");
165 for (part
= vtoc
->v_part
; part
< vtoc
->v_part
+ vtoc
->v_nparts
; ++part
)
166 if (part
->p_size
&& part
->p_tag
!= V_BACKUP
)
169 qsort((char *)sorted
, (uint_t
)(list
- sorted
),
170 sizeof (*sorted
), partcmp
);
172 freeidx
->fr_start
= 0;
173 for (list
= sorted
; (part
= *list
) != NULL
; ++list
)
174 if (part
->p_start
<= freeidx
->fr_start
)
175 freeidx
->fr_start
+= part
->p_size
;
177 freeidx
->fr_size
= part
->p_start
- freeidx
->fr_start
;
178 (++freeidx
)->fr_start
= part
->p_start
+ part
->p_size
;
180 if (freeidx
->fr_start
< fullsize
) {
181 freeidx
->fr_size
= fullsize
- freeidx
->fr_start
;
184 freeidx
->fr_start
= freeidx
->fr_size
= 0;
189 * findfree64(): Find free space on a disk.
192 findfree64(struct dk_gpt
*efi
)
194 struct dk_part
*part
;
195 struct dk_part
**list
;
198 struct dk_part
**sorted
;
200 freemap
= calloc(sizeof (freemap_t
), efi
->efi_nparts
+ 1);
201 sorted
= calloc(sizeof (struct dk_part
), efi
->efi_nparts
+ 1);
202 fullsize
= efi
->efi_last_u_lba
;
204 for (part
= efi
->efi_parts
;
205 part
< efi
->efi_parts
+ efi
->efi_nparts
;
207 if (part
->p_size
&& part
->p_tag
!= V_BACKUP
)
210 qsort((char *)sorted
, (uint_t
)(list
- sorted
),
211 sizeof (*sorted
), partcmp64
);
213 freeidx
->fr_start
= efi
->efi_first_u_lba
;
214 for (list
= sorted
; (part
= *list
) != NULL
; ++list
)
215 if (part
->p_start
== freeidx
->fr_start
)
216 freeidx
->fr_start
+= part
->p_size
;
218 freeidx
->fr_size
= part
->p_start
- freeidx
->fr_start
;
219 (++freeidx
)->fr_start
= part
->p_start
+ part
->p_size
;
221 if (freeidx
->fr_start
< fullsize
) {
222 freeidx
->fr_size
= fullsize
- freeidx
->fr_start
;
225 freeidx
->fr_start
= freeidx
->fr_size
= 0;
232 * Get the filesystem mountpoint of each partition on the disk
233 * from the fstab or mnttab. Returns a pointer to an array of pointers to
234 * directory names (indexed by partition number).
237 getmntpt(major_t slot
, minor_t nopartminor
)
241 char devbuf
[PATH_MAX
], *item
;
242 static char *list
[V_NUMPAR
];
247 for (idx
= 0; idx
< V_NUMPAR
; ++idx
)
250 /* read mnttab for partition mountpoints */
251 if ((file
= fopen(mnttab
, "r")) == NULL
) {
252 (void) warn(mnttab
, strerror(errno
));
254 while (getmntent(file
, &mtab
) == 0) {
255 item
= mtab
.mnt_special
;
256 if ((item
== NULL
) || (mtab
.mnt_mountp
== NULL
))
262 if (strncmp(item
, "/dev/", strlen("/dev/") != 0))
266 * Is it a character device?
268 (void) snprintf(devbuf
, sizeof (devbuf
), "/dev/r%s",
269 item
+ strlen("/dev/"));
271 if ((stat(devbuf
, &sb
) != 0) ||
272 ((sb
.st_mode
& S_IFMT
) != S_IFCHR
))
276 * device must match input slot and nopartminor
278 if ((major(sb
.st_rdev
) != slot
) ||
279 (noparttn(minor(sb
.st_rdev
)) != nopartminor
))
282 list
[parttn(minor(sb
.st_rdev
))] =
283 safe_strdup(mtab
.mnt_mountp
);
288 if ((file
= fopen(fstab
, "r")) == NULL
) {
289 (void) warn(fstab
, strerror(errno
));
294 * Look for the disk in the vfstab so that we can report its mount
295 * point even if it isn't currently mounted.
297 while (getvfsent(file
, &vtab
) == 0) {
298 item
= vtab
.vfs_special
;
299 if ((item
== NULL
) || (vtab
.vfs_mountp
== NULL
))
302 if (strncmp(item
, "/dev/", strlen("/dev/")) != 0)
306 * Is it a character device?
308 (void) snprintf(devbuf
, sizeof (devbuf
), "/dev/r%s",
309 item
+ strlen("/dev/"));
311 if ((stat(devbuf
, &sb
) != 0) ||
312 ((sb
.st_mode
& S_IFMT
) != S_IFCHR
))
316 * device must match input slot and nopartminor
318 if ((major(sb
.st_rdev
) != slot
) ||
319 (noparttn(minor(sb
.st_rdev
)) != nopartminor
))
323 * use mnttab entry if both tables have entries
325 if (list
[parttn(minor(sb
.st_rdev
))] != NULL
)
328 list
[parttn(minor(sb
.st_rdev
))] = safe_strdup(vtab
.vfs_mountp
);
336 * partcmp(): Qsort() key comparison of partitions by starting sector numbers.
339 partcmp(const void *one
, const void *two
)
341 return ((*(struct partition
**)one
)->p_start
-
342 (*(struct partition
**)two
)->p_start
);
346 partcmp64(const void *one
, const void *two
)
348 if ((*(struct dk_part
**)one
)->p_start
>
349 (*(struct dk_part
**)two
)->p_start
)
351 else if ((*(struct dk_part
**)one
)->p_start
<
352 (*(struct dk_part
**)two
)->p_start
)
360 * prtvtoc(): Read and print a VTOC.
363 prtvtoc(char *devname
)
376 name
= getfullrawname(devname
);
378 return (warn(devname
,
379 "internal administrative call (getfullrawname) failed"));
380 if (strcmp(name
, "") == 0)
382 if ((fd
= open(name
, O_NONBLOCK
|O_RDONLY
)) < 0)
383 return (warn(name
, strerror(errno
)));
384 if (fstat(fd
, &sb
) < 0)
385 return (warn(name
, strerror(errno
)));
386 if ((sb
.st_mode
& S_IFMT
) != S_IFCHR
)
387 return (warn(name
, "Not a raw device"));
389 geo
= (readgeom(fd
, name
, &geom
) == 0);
391 if ((idx
= readvtoc(fd
, name
, &vtoc
)) == VT_ENOTSUP
) {
392 idx
= (readefi(fd
, name
, &efi
) == 0);
398 if ((!geo
) || (!idx
))
401 freemap
= findfree(&geom
, &vtoc
);
403 freemap
= findfree64(efi
);
406 putfree(&vtoc
, freemap
);
408 putfree64(efi
, freemap
);
411 puttable(&geom
, &vtoc
, freemap
, devname
,
412 getmntpt(major(sb
.st_rdev
),
413 noparttn(minor(sb
.st_rdev
))));
415 puttable64(efi
, freemap
, devname
,
416 getmntpt(major(sb
.st_rdev
),
417 noparttn(minor(sb
.st_rdev
))));
427 * Print shell assignments for disk free space. FREE_START and FREE_SIZE
428 * represent the starting block and number of blocks of the first chunk
429 * of free space. FREE_PART lists the unassigned partitions.
432 putfree(struct extvtoc
*vtoc
, freemap_t
*freemap
)
438 for (freeidx
= freemap
; freeidx
->fr_size
; ++freeidx
)
441 (void) printf("FREE_START=%llu FREE_SIZE=%llu FREE_COUNT=%d FREE_PART=",
442 freemap
->fr_start
, freemap
->fr_size
, free_count
);
444 for (idx
= 0; idx
< vtoc
->v_nparts
; ++idx
) {
445 if (vtoc
->v_part
[idx
].p_size
== 0 && idx
!= 2)
446 (void) printf("%x", idx
);
452 putfree64(struct dk_gpt
*efi
, freemap_t
*freemap
)
458 for (freeidx
= freemap
; freeidx
->fr_size
; ++freeidx
)
461 (void) printf("FREE_START=%llu FREE_SIZE=%llu FREE_COUNT=%d FREE_PART=",
462 freemap
->fr_start
, freemap
->fr_size
, free_count
);
464 for (idx
= 0; idx
< efi
->efi_nparts
; ++idx
) {
465 if (efi
->efi_parts
[idx
].p_size
== 0 && idx
!= 2)
466 (void) printf("%x", idx
);
472 * puttable(): Print a human-readable VTOC.
475 puttable(struct dk_geom
*geom
, struct extvtoc
*vtoc
, freemap_t
*freemap
,
476 char *name
, char **mtab
)
481 cylsize
= (geom
->dkg_nsect
) * (geom
->dkg_nhead
);
482 if (!hflag
&& !sflag
) {
483 (void) printf("* %s", name
);
485 (void) printf(" (volume \"%.8s\")", vtoc
->v_volume
);
487 (void) printf(" partition map\n");
488 (void) printf("*\n* Dimensions:\n");
489 (void) printf("* %7u bytes/sector\n", vtoc
->v_sectorsz
);
490 (void) printf("* %7u sectors/track\n", geom
->dkg_nsect
);
491 (void) printf("* %7u tracks/cylinder\n", geom
->dkg_nhead
);
492 (void) printf("* %7lu sectors/cylinder\n", cylsize
);
493 (void) printf("* %7u cylinders\n", geom
->dkg_pcyl
);
494 (void) printf("* %7u accessible cylinders\n", geom
->dkg_ncyl
);
495 (void) printf("*\n* Flags:\n");
496 (void) printf("* 1: unmountable\n");
497 (void) printf("* 10: read-only\n*\n");
499 if (freemap
->fr_size
) {
500 (void) printf("* Unallocated space:\n");
501 (void) printf("*\tFirst Sector Last\n");
502 (void) printf("*\tSector Count Sector \n");
504 (void) printf("* %9llu %9llu %9llu\n",
505 freemap
->fr_start
, freemap
->fr_size
,
506 freemap
->fr_size
+ freemap
->fr_start
- 1);
507 } while ((++freemap
)->fr_size
);
508 (void) printf("*\n");
513 "* First Sector Last\n"
514 "* Partition Tag Flags Sector Count Sector Mount Directory\n");
516 for (idx
= 0; idx
< vtoc
->v_nparts
; ++idx
) {
517 if (vtoc
->v_part
[idx
].p_size
== 0)
519 (void) printf(" %2u %5u %02x %9llu %9llu %9llu",
520 idx
, vtoc
->v_part
[idx
].p_tag
, vtoc
->v_part
[idx
].p_flag
,
521 vtoc
->v_part
[idx
].p_start
, vtoc
->v_part
[idx
].p_size
,
522 vtoc
->v_part
[idx
].p_start
+ vtoc
->v_part
[idx
].p_size
- 1);
523 if (mtab
&& mtab
[idx
])
524 (void) printf(" %s", mtab
[idx
]);
530 * puttable(): Print a human-readable VTOC.
533 puttable64(struct dk_gpt
*efi
, freemap_t
*freemap
, char *name
,
538 if (!hflag
&& !sflag
) {
539 (void) printf("* %s", name
);
540 for (idx
= 0; idx
< efi
->efi_nparts
; idx
++)
541 if (efi
->efi_parts
[idx
].p_tag
== V_RESERVED
&&
542 *efi
->efi_parts
[idx
].p_name
)
543 (void) printf(" (volume \"%.8s\")",
544 efi
->efi_parts
[idx
].p_name
);
545 (void) printf(" partition map\n");
546 (void) printf("*\n* Dimensions:\n");
547 (void) printf("* %7u bytes/sector\n", efi
->efi_lbasize
);
548 (void) printf("* %llu sectors\n", efi
->efi_last_lba
+ 1);
549 (void) printf("* %llu accessible sectors\n",
550 efi
->efi_last_u_lba
- efi
->efi_first_u_lba
+ 1);
551 (void) printf("*\n* Flags:\n");
552 (void) printf("* 1: unmountable\n");
553 (void) printf("* 10: read-only\n*\n");
555 if (freemap
->fr_size
) {
556 (void) printf("* Unallocated space:\n");
557 (void) printf("*\tFirst Sector Last\n");
558 (void) printf("*\tSector Count Sector \n");
560 (void) printf("* %9llu %9llu %9llu\n",
561 freemap
->fr_start
, freemap
->fr_size
,
562 freemap
->fr_size
+ freemap
->fr_start
- 1);
563 } while ((++freemap
)->fr_size
);
564 (void) printf("*\n");
569 "* First Sector Last\n"
570 "* Partition Tag Flags Sector Count Sector Mount Directory\n");
572 for (idx
= 0; idx
< efi
->efi_nparts
; ++idx
) {
573 if (efi
->efi_parts
[idx
].p_size
== 0)
575 (void) printf(" %2u %5u %02x %9llu %9llu %9llu",
576 idx
, efi
->efi_parts
[idx
].p_tag
, efi
->efi_parts
[idx
].p_flag
,
577 efi
->efi_parts
[idx
].p_start
, efi
->efi_parts
[idx
].p_size
,
578 efi
->efi_parts
[idx
].p_start
+ efi
->efi_parts
[idx
].p_size
- 1);
579 if ((idx
< 7) && mtab
&& mtab
[idx
])
580 (void) printf(" %s", mtab
[idx
]);
586 * readgeom(): Read the disk geometry.
589 readgeom(int fd
, char *name
, struct dk_geom
*geom
)
591 char err_string
[128];
593 if ((ioctl(fd
, DKIOCGGEOM
, geom
) < 0) && (errno
!= ENOTSUP
)) {
594 (void) sprintf(err_string
,
595 "Unable to read Disk geometry errno = 0x%x",
597 return (warn(name
, err_string
));
598 } else if (errno
== ENOTSUP
) {
599 (void) memset(geom
, 0, sizeof (struct dk_geom
));
605 * readvtoc(): Read a partition map.
608 readvtoc(int fd
, char *name
, struct extvtoc
*vtoc
)
612 if ((retval
= read_extvtoc(fd
, vtoc
)) >= 0)
617 return (warn(name
, "Unable to read VTOC"));
619 return (warn(name
, "Invalid VTOC"));
621 return (warn(name
, "Unknown problem reading VTOC"));
627 * readefi(): Read a partition map.
630 readefi(int fd
, char *name
, struct dk_gpt
**efi
)
634 if ((retval
= efi_alloc_and_read(fd
, efi
)) >= 0)
639 return (warn(name
, "Unable to read VTOC"));
641 return (warn(name
, "Invalid VTOC"));
643 return (warn(name
, "Unknown problem reading VTOC"));
649 safe_strdup(char *str
)
652 if ((ret
= strdup(str
)) == NULL
) {
653 (void) warn("memory allocation", strerror(errno
));
660 * usage(): Print a helpful message and exit.
665 (void) fprintf(stderr
, "Usage:\t%s [ -fhs ] [ -t fstab ] [ -m mnttab ] "
666 "rawdisk ...\n", progname
);
671 * warn(): Print an error message. Always returns -1.
674 warn(char *what
, char *why
)
676 (void) fprintf(stderr
, "%s: %s: %s\n", progname
, what
, why
);