xref: /illumos-gate/usr/src/cmd/hal/utils/fsutils.c (revision 602ca9ea)
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