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
1318c2aff7Sartem #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)5518c2aff7Sartem 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