12912Sartem /*************************************************************************** 22912Sartem * 32912Sartem * fsutils.c : filesystem utilities 42912Sartem * 52912Sartem * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 62912Sartem * Use is subject to license terms. 72912Sartem * 82912Sartem * Licensed under the Academic Free License version 2.1 92912Sartem * 102912Sartem **************************************************************************/ 112912Sartem 12*2916Sartem #pragma ident "%Z%%M% %I% %E% SMI" 132912Sartem 142912Sartem #ifdef HAVE_CONFIG_H 152912Sartem # include <config.h> 162912Sartem #endif 172912Sartem 182912Sartem #include <stdio.h> 192912Sartem #include <sys/types.h> 202912Sartem #include <sys/scsi/impl/uscsi.h> 212912Sartem #include <string.h> 222912Sartem #include <strings.h> 232912Sartem #include <ctype.h> 242912Sartem #include <unistd.h> 252912Sartem #include <stdlib.h> 262912Sartem #include <errno.h> 272912Sartem #include <fcntl.h> 282912Sartem #include <sys/dkio.h> 292912Sartem #include <libintl.h> 302912Sartem #include <sys/dktp/fdisk.h> 312912Sartem #include <sys/fs/pc_label.h> 322912Sartem 332912Sartem #include <libhal.h> 342912Sartem #include "fsutils.h" 352912Sartem 362912Sartem /* 372912Sartem * Separates dos notation device spec into device and drive number 382912Sartem */ 392912Sartem boolean_t 402912Sartem dos_to_dev(char *path, char **devpath, int *num) 412912Sartem { 422912Sartem char *p; 432912Sartem 442912Sartem if ((p = strrchr(path, ':')) == NULL) { 452912Sartem return (B_FALSE); 462912Sartem } 472912Sartem if ((*num = atoi(p + 1)) == 0) { 482912Sartem return (B_FALSE); 492912Sartem } 502912Sartem p[0] = '\0'; 512912Sartem *devpath = strdup(path); 522912Sartem p[0] = ':'; 532912Sartem return (*devpath != NULL); 542912Sartem } 552912Sartem 562912Sartem char * 572912Sartem get_slice_name (char *devlink) 582912Sartem { 592912Sartem char *part, *slice, *disk; 602912Sartem char *s = NULL; 612912Sartem char *p; 622912Sartem 632912Sartem if ((p = strstr(devlink, "/lofi/")) != 0) { 642912Sartem return (p + sizeof ("/lofi/") - 1); 652912Sartem } 662912Sartem 672912Sartem part = strrchr(devlink, 'p'); 682912Sartem slice = strrchr(devlink, 's'); 692912Sartem disk = strrchr(devlink, 'd'); 702912Sartem 712912Sartem if ((part != NULL) && (part > slice) && (part > disk)) { 722912Sartem s = part; 732912Sartem } else if ((slice != NULL) && (slice > disk)) { 742912Sartem s = slice; 752912Sartem } else { 762912Sartem s = disk; 772912Sartem } 782912Sartem if ((s != NULL) && isdigit(s[1])) { 792912Sartem return (s); 802912Sartem } else { 812912Sartem return (""); 822912Sartem } 832912Sartem } 842912Sartem 852912Sartem boolean_t 862912Sartem is_dos_drive(uchar_t type) 872912Sartem { 882912Sartem return ((type == 1) || (type == 4) || (type == 5) || (type == 6) || 892912Sartem ((type >= 8) && (type <= 0xf))); 902912Sartem } 912912Sartem 922912Sartem boolean_t 932912Sartem is_dos_extended(uchar_t id) 942912Sartem { 952912Sartem return ((id == EXTDOS) || (id == FDISK_EXTLBA)); 962912Sartem } 972912Sartem 982912Sartem struct part_find_s { 992912Sartem int num; 1002912Sartem int count; 1012912Sartem int systid; 1022912Sartem int r_systid; 1032912Sartem int r_relsect; 1042912Sartem int r_numsect; 1052912Sartem }; 1062912Sartem 1072912Sartem enum { WALK_CONTINUE, WALK_TERMINATE }; 1082912Sartem 1092912Sartem /* 1102912Sartem * Walk partition tables and invoke a callback for each. 1112912Sartem */ 1122912Sartem static void 1132912Sartem walk_partitions(int fd, int startsec, int (*f)(void *, int, int, int), 1142912Sartem void *arg) 1152912Sartem { 1162912Sartem uint32_t buf[1024/4]; 1172912Sartem int bufsize = 1024; 1182912Sartem struct mboot *mboot = (struct mboot *)&buf[0]; 1192912Sartem struct ipart ipart[FD_NUMPART]; 1202912Sartem int sec = startsec; 1212912Sartem int lastsec = sec + 1; 1222912Sartem int relsect; 1232912Sartem int ext = 0; 1242912Sartem int systid; 1252912Sartem boolean_t valid; 1262912Sartem int i; 1272912Sartem 1282912Sartem while (sec != lastsec) { 1292912Sartem if (pread(fd, buf, bufsize, (off_t)sec * 512) != bufsize) { 1302912Sartem break; 1312912Sartem } 1322912Sartem lastsec = sec; 1332912Sartem if (ltohs(mboot->signature) != MBB_MAGIC) { 1342912Sartem break; 1352912Sartem } 1362912Sartem bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart)); 1372912Sartem 1382912Sartem for (i = 0; i < FD_NUMPART; i++) { 1392912Sartem systid = ipart[i].systid; 1402912Sartem relsect = sec + ltohi(ipart[i].relsect); 1412912Sartem if (systid == 0) { 1422912Sartem continue; 1432912Sartem } 1442912Sartem valid = B_TRUE; 1452912Sartem if (is_dos_extended(systid) && (sec == lastsec)) { 1462912Sartem sec = startsec + ltohi(ipart[i].relsect); 1472912Sartem if (ext++ == 0) { 1482912Sartem relsect = startsec = sec; 1492912Sartem } else { 1502912Sartem valid = B_FALSE; 1512912Sartem } 1522912Sartem } 1532912Sartem if (valid && f(arg, ipart[i].systid, relsect, 1542912Sartem ltohi(ipart[i].numsect)) == WALK_TERMINATE) { 1552912Sartem return; 1562912Sartem } 1572912Sartem } 1582912Sartem } 1592912Sartem } 1602912Sartem 1612912Sartem static int 1622912Sartem find_dos_drive_cb(void *arg, int systid, int relsect, int numsect) 1632912Sartem { 1642912Sartem struct part_find_s *p = arg; 1652912Sartem 1662912Sartem if (is_dos_drive(systid)) { 1672912Sartem if (++p->count == p->num) { 1682912Sartem p->r_relsect = relsect; 1692912Sartem p->r_numsect = numsect; 1702912Sartem p->r_systid = systid; 1712912Sartem return (WALK_TERMINATE); 1722912Sartem } 1732912Sartem } 1742912Sartem 1752912Sartem return (WALK_CONTINUE); 1762912Sartem } 1772912Sartem 1782912Sartem /* 1792912Sartem * Given a dos drive number, return its relative sector number, 1802912Sartem * number of sectors in partition and the system id. 1812912Sartem */ 1822912Sartem boolean_t 1832912Sartem find_dos_drive(int fd, int num, int *relsect, int *numsect, int *systid) 1842912Sartem { 1852912Sartem struct part_find_s p = { 0, 0, 0, 0, 0, 0 }; 1862912Sartem 1872912Sartem p.num = num; 1882912Sartem 1892912Sartem if (num > 0) { 1902912Sartem walk_partitions(fd, 0, find_dos_drive_cb, &p); 1912912Sartem if (p.count == num) { 1922912Sartem *relsect = p.r_relsect; 1932912Sartem *numsect = p.r_numsect; 1942912Sartem *systid = p.r_systid; 1952912Sartem return (B_TRUE); 1962912Sartem } 1972912Sartem } 1982912Sartem 1992912Sartem return (B_FALSE); 2002912Sartem } 2012912Sartem 2022912Sartem static int 2032912Sartem get_num_dos_drives_cb(void *arg, int systid, int relsect, int numsect) 2042912Sartem { 2052912Sartem if (is_dos_drive(systid)) { 2062912Sartem (*(int *)arg)++; 2072912Sartem } 2082912Sartem return (WALK_CONTINUE); 2092912Sartem } 2102912Sartem 2112912Sartem int 2122912Sartem get_num_dos_drives(int fd) 2132912Sartem { 2142912Sartem int count = 0; 2152912Sartem 2162912Sartem walk_partitions(fd, 0, get_num_dos_drives_cb, &count); 2172912Sartem 2182912Sartem return (count); 2192912Sartem } 2202912Sartem 2212912Sartem /* 2222912Sartem * Return true if all non-empty slices in vtoc have identical start/size and 2232912Sartem * are tagged backup/entire disk. 2242912Sartem */ 2252912Sartem boolean_t 2262912Sartem vtoc_one_slice_entire_disk(struct vtoc *vtoc) 2272912Sartem { 2282912Sartem int i; 2292912Sartem struct partition *p; 2302912Sartem daddr_t prev_start; 2312912Sartem long prev_size; 2322912Sartem 2332912Sartem for (i = 0; i < vtoc->v_nparts; i++) { 2342912Sartem p = &vtoc->v_part[i]; 2352912Sartem if (p->p_size == 0) { 2362912Sartem continue; 2372912Sartem } 2382912Sartem if ((p->p_tag != V_BACKUP) && ((p->p_tag != V_UNASSIGNED))) { 2392912Sartem return (B_FALSE); 2402912Sartem } 2412912Sartem if ((i > 0) && 2422912Sartem ((p->p_start != prev_start) || (p->p_size != prev_size))) { 2432912Sartem return (B_FALSE); 2442912Sartem } 2452912Sartem prev_start = p->p_start; 2462912Sartem prev_size = p->p_size; 2472912Sartem } 2482912Sartem 2492912Sartem return (B_TRUE); 2502912Sartem } 251