1 /* 2 * 3 * fsutils.c : filesystem utilities 4 * 5 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 6 * Use is subject to license terms. 7 * 8 * Licensed under the Academic Free License version 2.1 9 * 10 */ 11 12 #ifdef HAVE_CONFIG_H 13 #include <config.h> 14 #endif 15 16 #include <stdio.h> 17 #include <sys/types.h> 18 #include <sys/scsi/impl/uscsi.h> 19 #include <string.h> 20 #include <strings.h> 21 #include <ctype.h> 22 #include <unistd.h> 23 #include <stdlib.h> 24 #include <errno.h> 25 #include <fcntl.h> 26 #include <sys/dkio.h> 27 #include <libintl.h> 28 #include <sys/dktp/fdisk.h> 29 #include <sys/fs/pc_label.h> 30 31 #include <libhal.h> 32 #include "fsutils.h" 33 34 /* 35 * Separates dos notation device spec into device and drive number 36 */ 37 boolean_t 38 dos_to_dev(char *path, char **devpath, int *num) 39 { 40 char *p; 41 42 if ((p = strrchr(path, ':')) == NULL) { 43 return (B_FALSE); 44 } 45 if ((*num = atoi(p + 1)) == 0) { 46 return (B_FALSE); 47 } 48 p[0] = '\0'; 49 *devpath = strdup(path); 50 p[0] = ':'; 51 return (*devpath != NULL); 52 } 53 54 char * 55 get_slice_name(char *devlink) 56 { 57 char *part, *slice, *disk; 58 char *s = NULL; 59 char *p; 60 61 if ((p = strstr(devlink, "/lofi/")) != 0) { 62 return (p + sizeof ("/lofi/") - 1); 63 } 64 65 part = strrchr(devlink, 'p'); 66 slice = strrchr(devlink, 's'); 67 disk = strrchr(devlink, 'd'); 68 69 if ((part != NULL) && (part > slice) && (part > disk)) { 70 s = part; 71 } else if ((slice != NULL) && (slice > disk)) { 72 s = slice; 73 } else { 74 s = disk; 75 } 76 if ((s != NULL) && isdigit(s[1])) { 77 return (s); 78 } else { 79 return (""); 80 } 81 } 82 83 boolean_t 84 is_dos_drive(uchar_t type) 85 { 86 return ((type == DOSOS12) || (type == DOSOS16) || 87 (type == DOSHUGE) || (type == FDISK_WINDOWS) || 88 (type == FDISK_EXT_WIN) || (type == FDISK_FAT95) || 89 (type == DIAGPART)); 90 } 91 92 boolean_t 93 is_dos_extended(uchar_t id) 94 { 95 return ((id == EXTDOS) || (id == FDISK_EXTLBA)); 96 } 97 98 struct part_find_s { 99 int num; 100 int count; 101 int systid; 102 int r_systid; 103 uint_t r_relsect; 104 uint_t r_numsect; 105 }; 106 107 enum { WALK_CONTINUE, WALK_TERMINATE }; 108 109 /* 110 * Walk partition tables and invoke a callback for each. 111 */ 112 static void 113 walk_partitions(int fd, int startsec, uint_t secsz, 114 int (*f)(void *, int, uint_t, uint_t), void *arg) 115 { 116 uint32_t buf[1024/4]; 117 int bufsize = 1024; 118 struct mboot *mboot = (struct mboot *)&buf[0]; 119 struct ipart ipart[FD_NUMPART]; 120 uint_t sec = startsec; 121 uint_t lastsec = sec + 1; 122 uint_t relsect; 123 int ext = 0; 124 int systid; 125 boolean_t valid; 126 int i; 127 128 while (sec != lastsec) { 129 if (pread(fd, buf, bufsize, (off_t)sec * secsz) != bufsize) { 130 break; 131 } 132 lastsec = sec; 133 if (ltohs(mboot->signature) != MBB_MAGIC) { 134 break; 135 } 136 bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart)); 137 138 for (i = 0; i < FD_NUMPART; i++) { 139 systid = ipart[i].systid; 140 relsect = sec + ltohi(ipart[i].relsect); 141 if (systid == 0) { 142 continue; 143 } 144 valid = B_TRUE; 145 if (is_dos_extended(systid) && (sec == lastsec)) { 146 sec = startsec + ltohi(ipart[i].relsect); 147 if (ext++ == 0) { 148 relsect = startsec = sec; 149 } else { 150 valid = B_FALSE; 151 } 152 } 153 if (valid && f(arg, ipart[i].systid, relsect, 154 ltohi(ipart[i].numsect)) == WALK_TERMINATE) { 155 return; 156 } 157 } 158 } 159 } 160 161 static int 162 find_dos_drive_cb(void *arg, int systid, uint_t relsect, uint_t numsect) 163 { 164 struct part_find_s *p = arg; 165 166 if (is_dos_drive(systid)) { 167 if (++p->count == p->num) { 168 p->r_relsect = relsect; 169 p->r_numsect = numsect; 170 p->r_systid = systid; 171 return (WALK_TERMINATE); 172 } 173 } 174 175 return (WALK_CONTINUE); 176 } 177 178 /* 179 * Given a dos drive number, return its relative sector number, 180 * number of sectors in partition and the system id. 181 */ 182 boolean_t 183 find_dos_drive(int fd, int num, uint_t secsz, off_t *offset) 184 { 185 struct part_find_s p = { 0, 0, 0, 0, 0, 0 }; 186 187 p.num = num; 188 189 if (num > 0) { 190 walk_partitions(fd, 0, secsz, find_dos_drive_cb, &p); 191 if (p.count == num) { 192 *offset = (off_t)p.r_relsect * secsz; 193 return (B_TRUE); 194 } 195 } 196 197 return (B_FALSE); 198 } 199 200 static int 201 get_num_dos_drives_cb(void *arg, int systid, uint_t relsect, uint_t numsect) 202 { 203 if (is_dos_drive(systid)) { 204 (*(int *)arg)++; 205 } 206 return (WALK_CONTINUE); 207 } 208 209 int 210 get_num_dos_drives(int fd, uint_t secsz) 211 { 212 int count = 0; 213 214 walk_partitions(fd, 0, secsz, get_num_dos_drives_cb, &count); 215 216 return (count); 217 } 218 219 /* 220 * Return true if all non-empty slices in vtoc have identical start/size and 221 * are tagged backup/entire disk. 222 */ 223 boolean_t 224 vtoc_one_slice_entire_disk(struct extvtoc *vtoc) 225 { 226 int i; 227 struct extpartition *p; 228 diskaddr_t prev_start; 229 diskaddr_t prev_size; 230 231 for (i = 0; i < vtoc->v_nparts; i++) { 232 p = &vtoc->v_part[i]; 233 if (p->p_size == 0) { 234 continue; 235 } 236 if ((p->p_tag != V_BACKUP) && ((p->p_tag != V_UNASSIGNED))) { 237 return (B_FALSE); 238 } 239 if ((i > 0) && 240 ((p->p_start != prev_start) || (p->p_size != prev_size))) { 241 return (B_FALSE); 242 } 243 prev_start = p->p_start; 244 prev_size = p->p_size; 245 } 246 247 return (B_TRUE); 248 }