xref: /illumos-gate/usr/src/cmd/hal/utils/fsutils.c (revision 342440ec)
1*342440ecSPrasad Singamsetty /*
218c2aff7Sartem  *
318c2aff7Sartem  * fsutils.c : filesystem utilities
418c2aff7Sartem  *
5422ee277Sartem  * 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  *
10*342440ecSPrasad Singamsetty  */
1118c2aff7Sartem 
1218c2aff7Sartem #ifdef HAVE_CONFIG_H
13*342440ecSPrasad Singamsetty #include <config.h>
1418c2aff7Sartem #endif
1518c2aff7Sartem 
1618c2aff7Sartem #include <stdio.h>
1718c2aff7Sartem #include <sys/types.h>
1818c2aff7Sartem #include <sys/scsi/impl/uscsi.h>
1918c2aff7Sartem #include <string.h>
2018c2aff7Sartem #include <strings.h>
2118c2aff7Sartem #include <ctype.h>
2218c2aff7Sartem #include <unistd.h>
2318c2aff7Sartem #include <stdlib.h>
2418c2aff7Sartem #include <errno.h>
2518c2aff7Sartem #include <fcntl.h>
2618c2aff7Sartem #include <sys/dkio.h>
2718c2aff7Sartem #include <libintl.h>
2818c2aff7Sartem #include <sys/dktp/fdisk.h>
2918c2aff7Sartem #include <sys/fs/pc_label.h>
3018c2aff7Sartem 
3118c2aff7Sartem #include <libhal.h>
3218c2aff7Sartem #include "fsutils.h"
3318c2aff7Sartem 
3418c2aff7Sartem /*
3518c2aff7Sartem  * Separates dos notation device spec into device and drive number
3618c2aff7Sartem  */
3718c2aff7Sartem boolean_t
dos_to_dev(char * path,char ** devpath,int * num)3818c2aff7Sartem dos_to_dev(char *path, char **devpath, int *num)
3918c2aff7Sartem {
4018c2aff7Sartem 	char *p;
4118c2aff7Sartem 
4218c2aff7Sartem 	if ((p = strrchr(path, ':')) == NULL) {
4318c2aff7Sartem 		return (B_FALSE);
4418c2aff7Sartem 	}
4518c2aff7Sartem 	if ((*num = atoi(p + 1)) == 0) {
4618c2aff7Sartem 		return (B_FALSE);
4718c2aff7Sartem 	}
4818c2aff7Sartem 	p[0] = '\0';
4918c2aff7Sartem 	*devpath = strdup(path);
5018c2aff7Sartem 	p[0] = ':';
5118c2aff7Sartem 	return (*devpath != NULL);
5218c2aff7Sartem }
5318c2aff7Sartem 
5418c2aff7Sartem char *
get_slice_name(char * devlink)55*342440ecSPrasad Singamsetty get_slice_name(char *devlink)
5618c2aff7Sartem {
5718c2aff7Sartem 	char	*part, *slice, *disk;
5818c2aff7Sartem 	char	*s = NULL;
5918c2aff7Sartem 	char	*p;
6018c2aff7Sartem 
6118c2aff7Sartem 	if ((p = strstr(devlink, "/lofi/")) != 0) {
6218c2aff7Sartem 		return (p + sizeof ("/lofi/") - 1);
6318c2aff7Sartem 	}
6418c2aff7Sartem 
6518c2aff7Sartem 	part = strrchr(devlink, 'p');
6618c2aff7Sartem 	slice = strrchr(devlink, 's');
6718c2aff7Sartem 	disk = strrchr(devlink, 'd');
6818c2aff7Sartem 
6918c2aff7Sartem 	if ((part != NULL) && (part > slice) && (part > disk)) {
7018c2aff7Sartem 		s = part;
7118c2aff7Sartem 	} else if ((slice != NULL) && (slice > disk)) {
7218c2aff7Sartem 		s = slice;
7318c2aff7Sartem 	} else {
7418c2aff7Sartem 		s = disk;
7518c2aff7Sartem 	}
7618c2aff7Sartem 	if ((s != NULL) && isdigit(s[1])) {
7718c2aff7Sartem 		return (s);
7818c2aff7Sartem 	} else {
7918c2aff7Sartem 		return ("");
8018c2aff7Sartem 	}
8118c2aff7Sartem }
8218c2aff7Sartem 
8318c2aff7Sartem boolean_t
is_dos_drive(uchar_t type)8418c2aff7Sartem is_dos_drive(uchar_t type)
8518c2aff7Sartem {
86e5d31070Sartem 	return ((type == DOSOS12) || (type == DOSOS16) ||
87e5d31070Sartem 	    (type == DOSHUGE) || (type == FDISK_WINDOWS) ||
88e5d31070Sartem 	    (type == FDISK_EXT_WIN) || (type == FDISK_FAT95) ||
89e5d31070Sartem 	    (type == DIAGPART));
9018c2aff7Sartem }
9118c2aff7Sartem 
9218c2aff7Sartem boolean_t
is_dos_extended(uchar_t id)9318c2aff7Sartem is_dos_extended(uchar_t id)
9418c2aff7Sartem {
9518c2aff7Sartem 	return ((id == EXTDOS) || (id == FDISK_EXTLBA));
9618c2aff7Sartem }
9718c2aff7Sartem 
9818c2aff7Sartem struct part_find_s {
9918c2aff7Sartem 	int	num;
10018c2aff7Sartem 	int	count;
10118c2aff7Sartem 	int	systid;
10218c2aff7Sartem 	int	r_systid;
103*342440ecSPrasad Singamsetty 	uint_t	r_relsect;
104*342440ecSPrasad Singamsetty 	uint_t	r_numsect;
10518c2aff7Sartem };
10618c2aff7Sartem 
10718c2aff7Sartem enum { WALK_CONTINUE, WALK_TERMINATE };
10818c2aff7Sartem 
10918c2aff7Sartem /*
11018c2aff7Sartem  * Walk partition tables and invoke a callback for each.
11118c2aff7Sartem  */
11218c2aff7Sartem static void
walk_partitions(int fd,int startsec,uint_t secsz,int (* f)(void *,int,uint_t,uint_t),void * arg)113422ee277Sartem walk_partitions(int fd, int startsec, uint_t secsz,
114*342440ecSPrasad Singamsetty     int (*f)(void *, int, uint_t, uint_t), void *arg)
11518c2aff7Sartem {
11618c2aff7Sartem 	uint32_t buf[1024/4];
11718c2aff7Sartem 	int bufsize = 1024;
11818c2aff7Sartem 	struct mboot *mboot = (struct mboot *)&buf[0];
11918c2aff7Sartem 	struct ipart ipart[FD_NUMPART];
120*342440ecSPrasad Singamsetty 	uint_t sec = startsec;
121*342440ecSPrasad Singamsetty 	uint_t lastsec = sec + 1;
122*342440ecSPrasad Singamsetty 	uint_t relsect;
12318c2aff7Sartem 	int ext = 0;
12418c2aff7Sartem 	int systid;
12518c2aff7Sartem 	boolean_t valid;
12618c2aff7Sartem 	int i;
12718c2aff7Sartem 
12818c2aff7Sartem 	while (sec != lastsec) {
129422ee277Sartem 		if (pread(fd, buf, bufsize, (off_t)sec * secsz) != bufsize) {
13018c2aff7Sartem 			break;
13118c2aff7Sartem 		}
13218c2aff7Sartem 		lastsec = sec;
13318c2aff7Sartem 		if (ltohs(mboot->signature) != MBB_MAGIC) {
13418c2aff7Sartem 			break;
13518c2aff7Sartem 		}
13618c2aff7Sartem 		bcopy(mboot->parts, ipart, FD_NUMPART * sizeof (struct ipart));
13718c2aff7Sartem 
13818c2aff7Sartem 		for (i = 0; i < FD_NUMPART; i++) {
13918c2aff7Sartem 			systid = ipart[i].systid;
14018c2aff7Sartem 			relsect = sec + ltohi(ipart[i].relsect);
14118c2aff7Sartem 			if (systid == 0) {
14218c2aff7Sartem 				continue;
14318c2aff7Sartem 			}
14418c2aff7Sartem 			valid = B_TRUE;
14518c2aff7Sartem 			if (is_dos_extended(systid) && (sec == lastsec)) {
14618c2aff7Sartem 				sec = startsec + ltohi(ipart[i].relsect);
14718c2aff7Sartem 				if (ext++ == 0) {
14818c2aff7Sartem 					relsect = startsec = sec;
14918c2aff7Sartem 				} else {
15018c2aff7Sartem 					valid = B_FALSE;
15118c2aff7Sartem 				}
15218c2aff7Sartem 			}
15318c2aff7Sartem 			if (valid && f(arg, ipart[i].systid, relsect,
15418c2aff7Sartem 			    ltohi(ipart[i].numsect)) == WALK_TERMINATE) {
15518c2aff7Sartem 				return;
15618c2aff7Sartem 			}
15718c2aff7Sartem 		}
15818c2aff7Sartem 	}
15918c2aff7Sartem }
16018c2aff7Sartem 
16118c2aff7Sartem static int
find_dos_drive_cb(void * arg,int systid,uint_t relsect,uint_t numsect)162*342440ecSPrasad Singamsetty find_dos_drive_cb(void *arg, int systid, uint_t relsect, uint_t numsect)
16318c2aff7Sartem {
16418c2aff7Sartem 	struct part_find_s *p = arg;
16518c2aff7Sartem 
16618c2aff7Sartem 	if (is_dos_drive(systid)) {
16718c2aff7Sartem 		if (++p->count == p->num) {
16818c2aff7Sartem 			p->r_relsect = relsect;
16918c2aff7Sartem 			p->r_numsect = numsect;
17018c2aff7Sartem 			p->r_systid = systid;
17118c2aff7Sartem 			return (WALK_TERMINATE);
17218c2aff7Sartem 		}
17318c2aff7Sartem 	}
17418c2aff7Sartem 
17518c2aff7Sartem 	return (WALK_CONTINUE);
17618c2aff7Sartem }
17718c2aff7Sartem 
17818c2aff7Sartem /*
17918c2aff7Sartem  * Given a dos drive number, return its relative sector number,
18018c2aff7Sartem  * number of sectors in partition and the system id.
18118c2aff7Sartem  */
18218c2aff7Sartem boolean_t
find_dos_drive(int fd,int num,uint_t secsz,off_t * offset)183422ee277Sartem find_dos_drive(int fd, int num, uint_t secsz, off_t *offset)
18418c2aff7Sartem {
18518c2aff7Sartem 	struct part_find_s p = { 0, 0, 0, 0, 0, 0 };
18618c2aff7Sartem 
18718c2aff7Sartem 	p.num = num;
18818c2aff7Sartem 
18918c2aff7Sartem 	if (num > 0) {
190422ee277Sartem 		walk_partitions(fd, 0, secsz, find_dos_drive_cb, &p);
19118c2aff7Sartem 		if (p.count == num) {
192422ee277Sartem 			*offset = (off_t)p.r_relsect * secsz;
19318c2aff7Sartem 			return (B_TRUE);
19418c2aff7Sartem 		}
19518c2aff7Sartem 	}
19618c2aff7Sartem 
19718c2aff7Sartem 	return (B_FALSE);
19818c2aff7Sartem }
19918c2aff7Sartem 
20018c2aff7Sartem static int
get_num_dos_drives_cb(void * arg,int systid,uint_t relsect,uint_t numsect)201*342440ecSPrasad Singamsetty get_num_dos_drives_cb(void *arg, int systid, uint_t relsect, uint_t numsect)
20218c2aff7Sartem {
20318c2aff7Sartem 	if (is_dos_drive(systid)) {
20418c2aff7Sartem 		(*(int *)arg)++;
20518c2aff7Sartem 	}
20618c2aff7Sartem 	return (WALK_CONTINUE);
20718c2aff7Sartem }
20818c2aff7Sartem 
20918c2aff7Sartem int
get_num_dos_drives(int fd,uint_t secsz)210422ee277Sartem get_num_dos_drives(int fd, uint_t secsz)
21118c2aff7Sartem {
21218c2aff7Sartem 	int count = 0;
21318c2aff7Sartem 
214422ee277Sartem 	walk_partitions(fd, 0, secsz, get_num_dos_drives_cb, &count);
21518c2aff7Sartem 
21618c2aff7Sartem 	return (count);
21718c2aff7Sartem }
21818c2aff7Sartem 
21918c2aff7Sartem /*
22018c2aff7Sartem  * Return true if all non-empty slices in vtoc have identical start/size and
22118c2aff7Sartem  * are tagged backup/entire disk.
22218c2aff7Sartem  */
22318c2aff7Sartem boolean_t
vtoc_one_slice_entire_disk(struct extvtoc * vtoc)224*342440ecSPrasad Singamsetty vtoc_one_slice_entire_disk(struct extvtoc *vtoc)
22518c2aff7Sartem {
22618c2aff7Sartem 	int		i;
227*342440ecSPrasad Singamsetty 	struct extpartition *p;
228*342440ecSPrasad Singamsetty 	diskaddr_t	prev_start;
229*342440ecSPrasad Singamsetty 	diskaddr_t	prev_size;
23018c2aff7Sartem 
23118c2aff7Sartem 	for (i = 0; i < vtoc->v_nparts; i++) {
23218c2aff7Sartem 		p = &vtoc->v_part[i];
23318c2aff7Sartem 		if (p->p_size == 0) {
23418c2aff7Sartem 			continue;
23518c2aff7Sartem 		}
23618c2aff7Sartem 		if ((p->p_tag != V_BACKUP) && ((p->p_tag != V_UNASSIGNED))) {
23718c2aff7Sartem 			return (B_FALSE);
23818c2aff7Sartem 		}
23918c2aff7Sartem 		if ((i > 0) &&
24018c2aff7Sartem 		    ((p->p_start != prev_start) || (p->p_size != prev_size))) {
24118c2aff7Sartem 			return (B_FALSE);
24218c2aff7Sartem 		}
24318c2aff7Sartem 		prev_start = p->p_start;
24418c2aff7Sartem 		prev_size = p->p_size;
24518c2aff7Sartem 	}
24618c2aff7Sartem 
24718c2aff7Sartem 	return (B_TRUE);
24818c2aff7Sartem }
249