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
dos_to_dev(char * path,char ** devpath,int * num)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 *
get_slice_name(char * devlink)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
is_dos_drive(uchar_t type)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
is_dos_extended(uchar_t id)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
walk_partitions(int fd,int startsec,uint_t secsz,int (* f)(void *,int,uint_t,uint_t),void * arg)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
find_dos_drive_cb(void * arg,int systid,uint_t relsect,uint_t numsect)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
find_dos_drive(int fd,int num,uint_t secsz,off_t * offset)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
get_num_dos_drives_cb(void * arg,int systid,uint_t relsect,uint_t numsect)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
get_num_dos_drives(int fd,uint_t secsz)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
vtoc_one_slice_entire_disk(struct extvtoc * vtoc)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 }
249