xref: /illumos-gate/usr/src/cmd/hal/utils/fsutils.c (revision 24da5b34)
1 /***************************************************************************
2  *
3  * fsutils.c : filesystem utilities
4  *
5  * Copyright 2006 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, int (*f)(void *, int, int, int),
116     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 * 512) != 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, int *relsect, int *numsect, int *systid)
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, find_dos_drive_cb, &p);
193 		if (p.count == num) {
194 			*relsect = p.r_relsect;
195 			*numsect = p.r_numsect;
196 			*systid = p.r_systid;
197 			return (B_TRUE);
198 		}
199 	}
200 
201 	return (B_FALSE);
202 }
203 
204 static int
205 get_num_dos_drives_cb(void *arg, int systid, int relsect, int numsect)
206 {
207 	if (is_dos_drive(systid)) {
208 		(*(int *)arg)++;
209 	}
210 	return (WALK_CONTINUE);
211 }
212 
213 int
214 get_num_dos_drives(int fd)
215 {
216 	int count = 0;
217 
218 	walk_partitions(fd, 0, get_num_dos_drives_cb, &count);
219 
220 	return (count);
221 }
222 
223 /*
224  * Return true if all non-empty slices in vtoc have identical start/size and
225  * are tagged backup/entire disk.
226  */
227 boolean_t
228 vtoc_one_slice_entire_disk(struct vtoc *vtoc)
229 {
230 	int		i;
231 	struct partition *p;
232 	daddr_t		prev_start;
233 	long		prev_size;
234 
235 	for (i = 0; i < vtoc->v_nparts; i++) {
236 		p = &vtoc->v_part[i];
237 		if (p->p_size == 0) {
238 			continue;
239 		}
240 		if ((p->p_tag != V_BACKUP) && ((p->p_tag != V_UNASSIGNED))) {
241 			return (B_FALSE);
242 		}
243 		if ((i > 0) &&
244 		    ((p->p_start != prev_start) || (p->p_size != prev_size))) {
245 			return (B_FALSE);
246 		}
247 		prev_start = p->p_start;
248 		prev_size = p->p_size;
249 	}
250 
251 	return (B_TRUE);
252 }
253