12912Sartem /*************************************************************************** 22912Sartem * 32912Sartem * fsutils.c : filesystem utilities 42912Sartem * 5*6395Sartem * Copyright 2008 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 122916Sartem #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 { 883602Sartem return ((type == DOSOS12) || (type == DOSOS16) || 893602Sartem (type == DOSHUGE) || (type == FDISK_WINDOWS) || 903602Sartem (type == FDISK_EXT_WIN) || (type == FDISK_FAT95) || 913602Sartem (type == DIAGPART)); 922912Sartem } 932912Sartem 942912Sartem boolean_t 952912Sartem is_dos_extended(uchar_t id) 962912Sartem { 972912Sartem return ((id == EXTDOS) || (id == FDISK_EXTLBA)); 982912Sartem } 992912Sartem 1002912Sartem struct part_find_s { 1012912Sartem int num; 1022912Sartem int count; 1032912Sartem int systid; 1042912Sartem int r_systid; 1052912Sartem int r_relsect; 1062912Sartem int r_numsect; 1072912Sartem }; 1082912Sartem 1092912Sartem enum { WALK_CONTINUE, WALK_TERMINATE }; 1102912Sartem 1112912Sartem /* 1122912Sartem * Walk partition tables and invoke a callback for each. 1132912Sartem */ 1142912Sartem static void 115*6395Sartem walk_partitions(int fd, int startsec, uint_t secsz, 116*6395Sartem int (*f)(void *, int, int, int), void *arg) 1172912Sartem { 1182912Sartem uint32_t buf[1024/4]; 1192912Sartem int bufsize = 1024; 1202912Sartem struct mboot *mboot = (struct mboot *)&buf[0]; 1212912Sartem struct ipart ipart[FD_NUMPART]; 1222912Sartem int sec = startsec; 1232912Sartem int lastsec = sec + 1; 1242912Sartem int relsect; 1252912Sartem int ext = 0; 1262912Sartem int systid; 1272912Sartem boolean_t valid; 1282912Sartem int i; 1292912Sartem 1302912Sartem while (sec != lastsec) { 131*6395Sartem if (pread(fd, buf, bufsize, (off_t)sec * secsz) != bufsize) { 1322912Sartem break; 1332912Sartem } 1342912Sartem lastsec = sec; 1352912Sartem if (ltohs(mboot->signature) != MBB_MAGIC) { 1362912Sartem break; 1372912Sartem } 1382912Sartem bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart)); 1392912Sartem 1402912Sartem for (i = 0; i < FD_NUMPART; i++) { 1412912Sartem systid = ipart[i].systid; 1422912Sartem relsect = sec + ltohi(ipart[i].relsect); 1432912Sartem if (systid == 0) { 1442912Sartem continue; 1452912Sartem } 1462912Sartem valid = B_TRUE; 1472912Sartem if (is_dos_extended(systid) && (sec == lastsec)) { 1482912Sartem sec = startsec + ltohi(ipart[i].relsect); 1492912Sartem if (ext++ == 0) { 1502912Sartem relsect = startsec = sec; 1512912Sartem } else { 1522912Sartem valid = B_FALSE; 1532912Sartem } 1542912Sartem } 1552912Sartem if (valid && f(arg, ipart[i].systid, relsect, 1562912Sartem ltohi(ipart[i].numsect)) == WALK_TERMINATE) { 1572912Sartem return; 1582912Sartem } 1592912Sartem } 1602912Sartem } 1612912Sartem } 1622912Sartem 1632912Sartem static int 1642912Sartem find_dos_drive_cb(void *arg, int systid, int relsect, int numsect) 1652912Sartem { 1662912Sartem struct part_find_s *p = arg; 1672912Sartem 1682912Sartem if (is_dos_drive(systid)) { 1692912Sartem if (++p->count == p->num) { 1702912Sartem p->r_relsect = relsect; 1712912Sartem p->r_numsect = numsect; 1722912Sartem p->r_systid = systid; 1732912Sartem return (WALK_TERMINATE); 1742912Sartem } 1752912Sartem } 1762912Sartem 1772912Sartem return (WALK_CONTINUE); 1782912Sartem } 1792912Sartem 1802912Sartem /* 1812912Sartem * Given a dos drive number, return its relative sector number, 1822912Sartem * number of sectors in partition and the system id. 1832912Sartem */ 1842912Sartem boolean_t 185*6395Sartem find_dos_drive(int fd, int num, uint_t secsz, off_t *offset) 1862912Sartem { 1872912Sartem struct part_find_s p = { 0, 0, 0, 0, 0, 0 }; 1882912Sartem 1892912Sartem p.num = num; 1902912Sartem 1912912Sartem if (num > 0) { 192*6395Sartem walk_partitions(fd, 0, secsz, find_dos_drive_cb, &p); 1932912Sartem if (p.count == num) { 194*6395Sartem *offset = (off_t)p.r_relsect * secsz; 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 212*6395Sartem get_num_dos_drives(int fd, uint_t secsz) 2132912Sartem { 2142912Sartem int count = 0; 2152912Sartem 216*6395Sartem walk_partitions(fd, 0, secsz, 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