xref: /illumos-gate/usr/src/cmd/hal/utils/fsutils.c (revision 422ee277)
118c2aff7Sartem /***************************************************************************
218c2aff7Sartem  *
318c2aff7Sartem  * fsutils.c : filesystem utilities
418c2aff7Sartem  *
5*422ee277Sartem  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
618c2aff7Sartem  * Use is subject to license terms.
718c2aff7Sartem  *
818c2aff7Sartem  * Licensed under the Academic Free License version 2.1
918c2aff7Sartem  *
1018c2aff7Sartem  **************************************************************************/
1118c2aff7Sartem 
1292f38132Sartem #pragma ident	"%Z%%M%	%I%	%E% SMI"
1318c2aff7Sartem 
1418c2aff7Sartem #ifdef HAVE_CONFIG_H
1518c2aff7Sartem #  include <config.h>
1618c2aff7Sartem #endif
1718c2aff7Sartem 
1818c2aff7Sartem #include <stdio.h>
1918c2aff7Sartem #include <sys/types.h>
2018c2aff7Sartem #include <sys/scsi/impl/uscsi.h>
2118c2aff7Sartem #include <string.h>
2218c2aff7Sartem #include <strings.h>
2318c2aff7Sartem #include <ctype.h>
2418c2aff7Sartem #include <unistd.h>
2518c2aff7Sartem #include <stdlib.h>
2618c2aff7Sartem #include <errno.h>
2718c2aff7Sartem #include <fcntl.h>
2818c2aff7Sartem #include <sys/dkio.h>
2918c2aff7Sartem #include <libintl.h>
3018c2aff7Sartem #include <sys/dktp/fdisk.h>
3118c2aff7Sartem #include <sys/fs/pc_label.h>
3218c2aff7Sartem 
3318c2aff7Sartem #include <libhal.h>
3418c2aff7Sartem #include "fsutils.h"
3518c2aff7Sartem 
3618c2aff7Sartem /*
3718c2aff7Sartem  * Separates dos notation device spec into device and drive number
3818c2aff7Sartem  */
3918c2aff7Sartem boolean_t
4018c2aff7Sartem dos_to_dev(char *path, char **devpath, int *num)
4118c2aff7Sartem {
4218c2aff7Sartem 	char *p;
4318c2aff7Sartem 
4418c2aff7Sartem 	if ((p = strrchr(path, ':')) == NULL) {
4518c2aff7Sartem 		return (B_FALSE);
4618c2aff7Sartem 	}
4718c2aff7Sartem 	if ((*num = atoi(p + 1)) == 0) {
4818c2aff7Sartem 		return (B_FALSE);
4918c2aff7Sartem 	}
5018c2aff7Sartem 	p[0] = '\0';
5118c2aff7Sartem 	*devpath = strdup(path);
5218c2aff7Sartem 	p[0] = ':';
5318c2aff7Sartem 	return (*devpath != NULL);
5418c2aff7Sartem }
5518c2aff7Sartem 
5618c2aff7Sartem char *
5718c2aff7Sartem get_slice_name (char *devlink)
5818c2aff7Sartem {
5918c2aff7Sartem 	char	*part, *slice, *disk;
6018c2aff7Sartem 	char	*s = NULL;
6118c2aff7Sartem 	char	*p;
6218c2aff7Sartem 
6318c2aff7Sartem 	if ((p = strstr(devlink, "/lofi/")) != 0) {
6418c2aff7Sartem 		return (p + sizeof ("/lofi/") - 1);
6518c2aff7Sartem 	}
6618c2aff7Sartem 
6718c2aff7Sartem 	part = strrchr(devlink, 'p');
6818c2aff7Sartem 	slice = strrchr(devlink, 's');
6918c2aff7Sartem 	disk = strrchr(devlink, 'd');
7018c2aff7Sartem 
7118c2aff7Sartem 	if ((part != NULL) && (part > slice) && (part > disk)) {
7218c2aff7Sartem 		s = part;
7318c2aff7Sartem 	} else if ((slice != NULL) && (slice > disk)) {
7418c2aff7Sartem 		s = slice;
7518c2aff7Sartem 	} else {
7618c2aff7Sartem 		s = disk;
7718c2aff7Sartem 	}
7818c2aff7Sartem 	if ((s != NULL) && isdigit(s[1])) {
7918c2aff7Sartem 		return (s);
8018c2aff7Sartem 	} else {
8118c2aff7Sartem 		return ("");
8218c2aff7Sartem 	}
8318c2aff7Sartem }
8418c2aff7Sartem 
8518c2aff7Sartem boolean_t
8618c2aff7Sartem is_dos_drive(uchar_t type)
8718c2aff7Sartem {
88e5d31070Sartem 	return ((type == DOSOS12) || (type == DOSOS16) ||
89e5d31070Sartem 	    (type == DOSHUGE) || (type == FDISK_WINDOWS) ||
90e5d31070Sartem 	    (type == FDISK_EXT_WIN) || (type == FDISK_FAT95) ||
91e5d31070Sartem 	    (type == DIAGPART));
9218c2aff7Sartem }
9318c2aff7Sartem 
9418c2aff7Sartem boolean_t
9518c2aff7Sartem is_dos_extended(uchar_t id)
9618c2aff7Sartem {
9718c2aff7Sartem 	return ((id == EXTDOS) || (id == FDISK_EXTLBA));
9818c2aff7Sartem }
9918c2aff7Sartem 
10018c2aff7Sartem struct part_find_s {
10118c2aff7Sartem 	int	num;
10218c2aff7Sartem 	int	count;
10318c2aff7Sartem 	int	systid;
10418c2aff7Sartem 	int	r_systid;
10518c2aff7Sartem 	int	r_relsect;
10618c2aff7Sartem 	int	r_numsect;
10718c2aff7Sartem };
10818c2aff7Sartem 
10918c2aff7Sartem enum { WALK_CONTINUE, WALK_TERMINATE };
11018c2aff7Sartem 
11118c2aff7Sartem /*
11218c2aff7Sartem  * Walk partition tables and invoke a callback for each.
11318c2aff7Sartem  */
11418c2aff7Sartem static void
115*422ee277Sartem walk_partitions(int fd, int startsec, uint_t secsz,
116*422ee277Sartem     int (*f)(void *, int, int, int), void *arg)
11718c2aff7Sartem {
11818c2aff7Sartem 	uint32_t buf[1024/4];
11918c2aff7Sartem 	int bufsize = 1024;
12018c2aff7Sartem 	struct mboot *mboot = (struct mboot *)&buf[0];
12118c2aff7Sartem 	struct ipart ipart[FD_NUMPART];
12218c2aff7Sartem 	int sec = startsec;
12318c2aff7Sartem 	int lastsec = sec + 1;
12418c2aff7Sartem 	int relsect;
12518c2aff7Sartem 	int ext = 0;
12618c2aff7Sartem 	int systid;
12718c2aff7Sartem 	boolean_t valid;
12818c2aff7Sartem 	int i;
12918c2aff7Sartem 
13018c2aff7Sartem 	while (sec != lastsec) {
131*422ee277Sartem 		if (pread(fd, buf, bufsize, (off_t)sec * secsz) != bufsize) {
13218c2aff7Sartem 			break;
13318c2aff7Sartem 		}
13418c2aff7Sartem 		lastsec = sec;
13518c2aff7Sartem 		if (ltohs(mboot->signature) != MBB_MAGIC) {
13618c2aff7Sartem 			break;
13718c2aff7Sartem 		}
13818c2aff7Sartem 		bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart));
13918c2aff7Sartem 
14018c2aff7Sartem 		for (i = 0; i < FD_NUMPART; i++) {
14118c2aff7Sartem 			systid = ipart[i].systid;
14218c2aff7Sartem 			relsect = sec + ltohi(ipart[i].relsect);
14318c2aff7Sartem 			if (systid == 0) {
14418c2aff7Sartem 				continue;
14518c2aff7Sartem 			}
14618c2aff7Sartem 			valid = B_TRUE;
14718c2aff7Sartem 			if (is_dos_extended(systid) && (sec == lastsec)) {
14818c2aff7Sartem 				sec = startsec + ltohi(ipart[i].relsect);
14918c2aff7Sartem 				if (ext++ == 0) {
15018c2aff7Sartem 					relsect = startsec = sec;
15118c2aff7Sartem 				} else {
15218c2aff7Sartem 					valid = B_FALSE;
15318c2aff7Sartem 				}
15418c2aff7Sartem 			}
15518c2aff7Sartem 			if (valid && f(arg, ipart[i].systid, relsect,
15618c2aff7Sartem 			    ltohi(ipart[i].numsect)) == WALK_TERMINATE) {
15718c2aff7Sartem 				return;
15818c2aff7Sartem 			}
15918c2aff7Sartem 		}
16018c2aff7Sartem 	}
16118c2aff7Sartem }
16218c2aff7Sartem 
16318c2aff7Sartem static int
16418c2aff7Sartem find_dos_drive_cb(void *arg, int systid, int relsect, int numsect)
16518c2aff7Sartem {
16618c2aff7Sartem 	struct part_find_s *p = arg;
16718c2aff7Sartem 
16818c2aff7Sartem 	if (is_dos_drive(systid)) {
16918c2aff7Sartem 		if (++p->count == p->num) {
17018c2aff7Sartem 			p->r_relsect = relsect;
17118c2aff7Sartem 			p->r_numsect = numsect;
17218c2aff7Sartem 			p->r_systid = systid;
17318c2aff7Sartem 			return (WALK_TERMINATE);
17418c2aff7Sartem 		}
17518c2aff7Sartem 	}
17618c2aff7Sartem 
17718c2aff7Sartem 	return (WALK_CONTINUE);
17818c2aff7Sartem }
17918c2aff7Sartem 
18018c2aff7Sartem /*
18118c2aff7Sartem  * Given a dos drive number, return its relative sector number,
18218c2aff7Sartem  * number of sectors in partition and the system id.
18318c2aff7Sartem  */
18418c2aff7Sartem boolean_t
185*422ee277Sartem find_dos_drive(int fd, int num, uint_t secsz, off_t *offset)
18618c2aff7Sartem {
18718c2aff7Sartem 	struct part_find_s p = { 0, 0, 0, 0, 0, 0 };
18818c2aff7Sartem 
18918c2aff7Sartem 	p.num = num;
19018c2aff7Sartem 
19118c2aff7Sartem 	if (num > 0) {
192*422ee277Sartem 		walk_partitions(fd, 0, secsz, find_dos_drive_cb, &p);
19318c2aff7Sartem 		if (p.count == num) {
194*422ee277Sartem 			*offset = (off_t)p.r_relsect * secsz;
19518c2aff7Sartem 			return (B_TRUE);
19618c2aff7Sartem 		}
19718c2aff7Sartem 	}
19818c2aff7Sartem 
19918c2aff7Sartem 	return (B_FALSE);
20018c2aff7Sartem }
20118c2aff7Sartem 
20218c2aff7Sartem static int
20318c2aff7Sartem get_num_dos_drives_cb(void *arg, int systid, int relsect, int numsect)
20418c2aff7Sartem {
20518c2aff7Sartem 	if (is_dos_drive(systid)) {
20618c2aff7Sartem 		(*(int *)arg)++;
20718c2aff7Sartem 	}
20818c2aff7Sartem 	return (WALK_CONTINUE);
20918c2aff7Sartem }
21018c2aff7Sartem 
21118c2aff7Sartem int
212*422ee277Sartem get_num_dos_drives(int fd, uint_t secsz)
21318c2aff7Sartem {
21418c2aff7Sartem 	int count = 0;
21518c2aff7Sartem 
216*422ee277Sartem 	walk_partitions(fd, 0, secsz, get_num_dos_drives_cb, &count);
21718c2aff7Sartem 
21818c2aff7Sartem 	return (count);
21918c2aff7Sartem }
22018c2aff7Sartem 
22118c2aff7Sartem /*
22218c2aff7Sartem  * Return true if all non-empty slices in vtoc have identical start/size and
22318c2aff7Sartem  * are tagged backup/entire disk.
22418c2aff7Sartem  */
22518c2aff7Sartem boolean_t
22618c2aff7Sartem vtoc_one_slice_entire_disk(struct vtoc *vtoc)
22718c2aff7Sartem {
22818c2aff7Sartem 	int		i;
22918c2aff7Sartem 	struct partition *p;
23018c2aff7Sartem 	daddr_t		prev_start;
23118c2aff7Sartem 	long		prev_size;
23218c2aff7Sartem 
23318c2aff7Sartem 	for (i = 0; i < vtoc->v_nparts; i++) {
23418c2aff7Sartem 		p = &vtoc->v_part[i];
23518c2aff7Sartem 		if (p->p_size == 0) {
23618c2aff7Sartem 			continue;
23718c2aff7Sartem 		}
23818c2aff7Sartem 		if ((p->p_tag != V_BACKUP) && ((p->p_tag != V_UNASSIGNED))) {
23918c2aff7Sartem 			return (B_FALSE);
24018c2aff7Sartem 		}
24118c2aff7Sartem 		if ((i > 0) &&
24218c2aff7Sartem 		    ((p->p_start != prev_start) || (p->p_size != prev_size))) {
24318c2aff7Sartem 			return (B_FALSE);
24418c2aff7Sartem 		}
24518c2aff7Sartem 		prev_start = p->p_start;
24618c2aff7Sartem 		prev_size = p->p_size;
24718c2aff7Sartem 	}
24818c2aff7Sartem 
24918c2aff7Sartem 	return (B_TRUE);
25018c2aff7Sartem }
251