fsutils.c revision 2912:85ea316d9c18
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 */
39boolean_t
40dos_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
56char *
57get_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
85boolean_t
86is_dos_drive(uchar_t type)
87{
88	return ((type == 1) || (type == 4) || (type == 5) || (type == 6) ||
89	    ((type >= 8) && (type <= 0xf)));
90}
91
92boolean_t
93is_dos_extended(uchar_t id)
94{
95	return ((id == EXTDOS) || (id == FDISK_EXTLBA));
96}
97
98struct part_find_s {
99	int	num;
100	int	count;
101	int	systid;
102	int	r_systid;
103	int	r_relsect;
104	int	r_numsect;
105};
106
107enum { WALK_CONTINUE, WALK_TERMINATE };
108
109/*
110 * Walk partition tables and invoke a callback for each.
111 */
112static void
113walk_partitions(int fd, int startsec, int (*f)(void *, int, int, int),
114    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	int sec = startsec;
121	int lastsec = sec + 1;
122	int 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 * 512) != 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
161static int
162find_dos_drive_cb(void *arg, int systid, int relsect, int 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 */
182boolean_t
183find_dos_drive(int fd, int num, int *relsect, int *numsect, int *systid)
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, find_dos_drive_cb, &p);
191		if (p.count == num) {
192			*relsect = p.r_relsect;
193			*numsect = p.r_numsect;
194			*systid = p.r_systid;
195			return (B_TRUE);
196		}
197	}
198
199	return (B_FALSE);
200}
201
202static int
203get_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
211int
212get_num_dos_drives(int fd)
213{
214	int count = 0;
215
216	walk_partitions(fd, 0, 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 */
225boolean_t
226vtoc_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