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