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