#include <sys/types.h>
#include <ctype.h>
#include <sys/vtoc.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <memory.h>
#include <dirent.h>
#include <sys/fcntl.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <stdio.h>
#include <sys/dkio.h>
#include <priv_utils.h>
#include "rmformat.h"
extern void my_perror(char *err_string);
static int32_t last_token_type = 0;
#define spc() (last_token_type)
static int32_t data_lineno;
#define CHG_MODE_UNDEFINED (-1)
#define CHG_MODE_SET 0
#define CHG_MODE_CLR 1
#define CHG_MODE_ABS 2
#define TOKEN_SIZE 36
typedef char TOKEN[TOKEN_SIZE+1];
#define DATA_INPUT 0
#define CMD_INPUT 1
#define WILD_STRING "$"
#define COMMENT_CHAR '#'
typedef struct slist {
char *str;
char *help;
int32_t value;
} slist_t;
static slist_t ptag_choices[] = {
{ "unassigned", "", V_UNASSIGNED },
{ "boot", "", V_BOOT },
{ "root", "", V_ROOT },
{ "swap", "", V_SWAP },
{ "usr", "", V_USR },
{ "backup", "", V_BACKUP },
{ "stand", "", V_STAND },
{ "var", "", V_VAR },
{ "home", "", V_HOME },
{ "alternates", "", V_ALTSCTR },
{ NULL }
};
static slist_t pflag_choices[] = {
{ "wm", "read-write, mountable", 0 },
{ "wu", "read-write, unmountable", V_UNMNT },
{ "rm", "read-only, mountable", V_RONLY },
{ "ru", "read-only, unmountable", V_RONLY|V_UNMNT },
{ NULL }
};
#define SUP_EOF -1
#define SUP_STRING 0
#define SUP_EQL 1
#define SUP_COMMA 2
#define SUP_COLON 3
#define SUP_EOL 4
#define SUP_OR 5
#define SUP_AND 6
#define SUP_TILDE 7
static int32_t sup_prxfile(char *file_name, struct extvtoc *vt);
static int32_t sup_setpart(struct extvtoc *vt);
static void sup_pushchar(int32_t c);
static void clean_token(char *cleantoken, char *token);
static void clean_token(char *cleantoken, char *token);
static int32_t sup_inputchar();
static int32_t sup_gettoken(char *buf);
static int32_t sup_get_token(char *buf);
static int32_t find_value(slist_t *slist, char *str, int32_t *value);
static int32_t check_vtoc_sanity(smedia_handle_t, int32_t fd,
struct extvtoc *vt);
static uint64_t str2sector(char *str);
static int32_t strcnt(char *s1, char *s2);
static int32_t get_fdisk(smedia_handle_t, int32_t fd, int32_t offset,
struct fdisk_info *fdisk);
static void erase(smedia_handle_t handle, diskaddr_t offset, diskaddr_t size);
extern char *myname;
extern uint64_t my_atoll(char *ptr);
extern smmedium_prop_t med_info;
static FILE *data_file;
static int32_t
sup_prxfile(char *file_name, struct extvtoc *vt)
{
int32_t status, ret_val;
TOKEN token;
TOKEN cleaned;
data_file = fopen(file_name, "r");
if (data_file == NULL) {
PERROR("Open failed");
return (-1);
}
data_lineno = 1;
for (;;) {
status = sup_gettoken(token);
if (status == SUP_EOF)
break;
if (status != SUP_STRING) {
(void) fprintf(stderr,
gettext("Expecting keyword, found '%s'"),
token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
continue;
}
clean_token(cleaned, token);
if (strcmp(cleaned, "slices") == 0) {
ret_val = sup_setpart(vt);
(void) fclose(data_file);
return (ret_val);
} else {
(void) fprintf(stderr, gettext("Unknown keyword '%s'"),
cleaned);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
(void) fclose(data_file);
return (-1);
}
}
(void) fclose(data_file);
(void) fprintf(stderr,
gettext("Unexpected end of file (line no %d)\n"), data_lineno);
return (-1);
}
static int32_t
sup_gettoken(char *buf)
{
while ((last_token_type = sup_get_token(buf)) == SUP_EOL)
;
return (last_token_type);
}
static int32_t
sup_get_token(char *buf)
{
char *ptr = buf;
int32_t c, quoted = 0;
if (feof(data_file)) {
return (SUP_EOF);
}
bzero(buf, TOKEN_SIZE + 1);
while (isspace(c = sup_inputchar()))
;
if (feof(data_file)) {
return (SUP_EOF);
}
for (; !isspace(c) || quoted; c = sup_inputchar()) {
if (feof(data_file)) {
if (ptr - buf > 0) {
return (SUP_STRING);
} else {
return (SUP_EOF);
}
}
if (c == '"') {
quoted = !quoted;
continue;
}
if (c == '\n')
break;
if (!quoted && (c == '=' || c == ',' || c == ':' ||
c == '#' || c == '|' || c == '&' || c == '~'))
break;
if (ptr - buf < TOKEN_SIZE)
*ptr++ = (char)c;
}
if (ptr - buf > 0) {
sup_pushchar(c);
return (SUP_STRING);
}
buf[0] = c;
switch (c) {
case '=':
return (SUP_EQL);
case ':':
return (SUP_COLON);
case ',':
return (SUP_COMMA);
case '\n':
return (SUP_EOL);
case '|':
return (SUP_OR);
case '&':
return (SUP_AND);
case '~':
return (SUP_TILDE);
case '#':
while ((c = sup_inputchar()) != '\n' && !feof(data_file))
;
if (feof(data_file))
return (SUP_EOF);
else
return (SUP_EOL);
default:
return (SUP_STRING);
}
}
static int32_t
sup_inputchar()
{
int32_t c;
c = getc(data_file);
if (c == '\\')
c = getc(data_file);
if (c == '\n') {
data_lineno++;
}
return (c);
}
static void
sup_pushchar(int32_t c)
{
(void) ungetc(c, data_file);
if (c == '\n')
data_lineno--;
}
static void
clean_token(char *cleantoken, char *token)
{
char *ptr;
for (ptr = token; isspace(*ptr) && (ptr <=
(token + strlen(token) - 1)); ptr++)
;
(void) strcpy(cleantoken, ptr);
for (ptr = cleantoken + strlen(cleantoken) - 1;
isspace(*ptr) && (ptr >= cleantoken); ptr--) {
*ptr = '\0';
}
}
static int32_t
sup_setpart(struct extvtoc *vt)
{
TOKEN token, cleaned, ident;
int32_t i, index, status;
uint64_t val1, val2;
ushort_t vtoc_tag = 0xFFFF;
ushort_t vtoc_flag = 0xFFFF;
status = sup_gettoken(token);
if (status != SUP_COLON) {
(void) fprintf(stderr,
gettext("Expecting ':', found '%s'"), token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
for (;;) {
status = sup_gettoken(token);
if (status != SUP_STRING) {
(void) fprintf(stderr,
gettext("Expecting string, found '%s'"), token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
clean_token(ident, token);
index = (int32_t)my_atoll(ident);
if ((index < 0) || (index >= NDKMAP)) {
(void) fprintf(stderr,
gettext("Unknown partition %d"), index);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
if (med_info.sm_media_type == SM_FLOPPY) {
if ((index < 0) || (index > 2)) {
(void) fprintf(stderr, gettext(
"Floppy can have partitions 0 1 and 2\n"));
return (-1);
}
}
if (med_info.sm_media_type == SM_PCMCIA_MEM) {
if (index != 2) {
(void) fprintf(stderr, gettext(
"PCMCIA Memory cards can have partition 2 only.\n"));
return (-1);
}
}
DPRINTF1("\n Partition %d: ", index);
status = sup_gettoken(token);
if (status != SUP_EQL) {
(void) fprintf(stderr,
gettext("Expecting '=', found '%s'"), token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
status = sup_gettoken(token);
if (status != SUP_STRING) {
(void) fprintf(stderr,
gettext("Expecting value, found '%s'"), token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
clean_token(cleaned, token);
val1 = str2sector(cleaned);
if (val1 == -1) {
(void) fprintf(stderr,
gettext("Invalid partition beggining %s \n"),
cleaned);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
}
DPRINTF1(" begins %s", cleaned);
status = sup_gettoken(token);
if (status != SUP_COMMA) {
(void) fprintf(stderr,
gettext("Expecting ', ', found '%s'"), token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
status = sup_gettoken(token);
if (status != SUP_STRING) {
(void) fprintf(stderr,
gettext("Expecting value, found '%s'"), token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
clean_token(cleaned, token);
val2 = str2sector(cleaned);
if (val2 == -1) {
(void) fprintf(stderr,
gettext("Invalid partition size %s \n"),
cleaned);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
}
DPRINTF1(" ends %s ", cleaned);
status = sup_gettoken(token);
if (status == SUP_COMMA) {
status = sup_gettoken(token);
if (status != SUP_STRING) {
(void) fprintf(stderr,
gettext("Expecting value, found '%s'"),
token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
clean_token(cleaned, token);
if (find_value(pflag_choices, cleaned, &i) == 1) {
DPRINTF1(" flag = %s", cleaned);
vtoc_flag = (ushort_t)i;
status = sup_gettoken(token);
} else if (find_value(ptag_choices, cleaned, &i) == 1) {
DPRINTF1(" tag = %s", cleaned);
vtoc_tag = (ushort_t)i;
status = sup_gettoken(token);
if (status == SUP_COMMA) {
(void) fprintf(stderr,
gettext("Expecting : got %s\n"),
token);
(void) fprintf(stderr,
gettext("Line no %d\n"),
data_lineno);
return (-1);
}
} else {
(void) fprintf(stderr,
gettext("Invalid flag or tag\n"));
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
if (status == SUP_COMMA) {
status = sup_gettoken(token);
if (status != SUP_STRING) {
(void) fprintf(stderr,
gettext("Expecting value"
", found '%s'"),
token);
(void) fprintf(stderr,
gettext("Line no %d\n"),
data_lineno);
return (-1);
}
clean_token(cleaned, token);
if (find_value(ptag_choices,
cleaned, &i) == 1) {
DPRINTF1(" tag = %s", cleaned);
vtoc_tag = (ushort_t)i;
}
status = sup_gettoken(token);
}
}
vt->v_part[index].p_start = val1;
vt->v_part[index].p_size = val2;
if (vtoc_tag != 0xFFFF) {
vt->v_part[index].p_tag = vtoc_tag;
vtoc_tag = 0xFFFF;
}
if (vtoc_flag != 0xFFFF) {
vt->v_part[index].p_flag = vtoc_flag;
vtoc_flag = 0xFFFF;
}
if (status == SUP_EOF) {
DPRINTF("\nEnd of file\n");
break;
}
if (status != SUP_COLON) {
(void) fprintf(stderr,
gettext("Expecting ':', found '%s'"), token);
(void) fprintf(stderr,
gettext("Line no %d\n"), data_lineno);
return (-1);
}
}
return (0);
}
static int32_t
find_value(slist_t *slist, char *match_str, int32_t *match_value)
{
int32_t i;
int32_t nmatches;
int32_t length;
int32_t match_length;
nmatches = 0;
length = 0;
match_length = strlen(match_str);
for (; slist->str != NULL; slist++) {
i = strcnt(match_str, slist->str);
if (i < match_length) {
continue;
}
if (i == length)
nmatches++;
if (i > length) {
*match_value = slist->value;
nmatches = 1;
length = i;
}
}
return (nmatches);
}
static int32_t
strcnt(char *s1, char *s2)
{
int32_t i = 0;
while ((*s1 != '\0') && (*s1++ == *s2++))
i++;
return (i);
}
static uint64_t
str2sector(char *str)
{
int32_t mul_factor = 1;
char *s1, *s2, *base;
uint64_t num_sectors;
uint64_t size;
base = s2 = (char *)malloc(strlen(str) + 1);
if (s2 == NULL) {
PERROR("Malloc failed");
return (-1);
}
*s2 = '\0';
s1 = str;
while (*s1) {
if ((*s1 != 'x') && ((*s1 < 'A') || (*s1 > 'F')) &&
((*s1 < 'a') || (*s1 > 'f')) && ((*s1 < '0') ||
(*s1 > '9'))) {
if (*s1 == 'G') {
mul_factor = 1024*1024*1024;
s1++;
} else if (*s1 == 'M') {
mul_factor = 1024*1024;
s1++;
} else if (*s1 == 'K') {
mul_factor = 1024;
s1++;
}
if ((*s1 != 'B') || (*(++s1) != '\0')) {
(void) fprintf(stderr,
gettext("Extra chars at the end\n"));
free(base);
return (-1);
}
break;
} else {
*s2++ = *s1++;
*s2 = '\0';
}
}
*s2 = '\0';
size = my_atoll(base);
if ((!mul_factor) || (size == -1)) {
free(base);
return (-1);
}
num_sectors = size * (uint64_t)mul_factor /512;
free(base);
return (num_sectors);
}
int32_t
valid_slice_file(smedia_handle_t handle, int32_t fd, char *file_name,
struct extvtoc *vt)
{
struct stat status;
int32_t ret_val;
if (stat(file_name, &status)) {
PERROR(file_name);
return (-1);
}
(void) memset(vt, 0, sizeof (*vt));
#ifdef sparc
vt->v_part[0].p_tag = V_ROOT;
vt->v_part[1].p_tag = V_SWAP;
vt->v_part[2].p_tag = V_BACKUP;
vt->v_part[6].p_tag = V_USR;
vt->v_part[1].p_flag = V_UNMNT;
vt->v_part[2].p_flag = V_UNMNT;
#endif
ret_val = sup_prxfile(file_name, vt);
if (ret_val < 0)
return (-1);
#ifdef DEBUG
{
int32_t i;
for (i = 0; i < 8; i++) {
DPRINTF1("\npart %d\n", i);
DPRINTF1("\t start %llu", vt->v_part[i].p_start);
DPRINTF1("\t size %llu ", vt->v_part[i].p_size);
DPRINTF1("\t tag %d", vt->v_part[i].p_tag);
DPRINTF1("\t flag %d", vt->v_part[i].p_flag);
}
}
#endif
if (check_vtoc_sanity(handle, fd, vt) < 0) {
return (-1);
}
#ifdef DEBUG
{
int32_t i;
for (i = 0; i < 8; i++) {
DPRINTF1("\npart %d\n", i);
DPRINTF1("\t start %llu", vt->v_part[i].p_start);
DPRINTF1("\t size %llu ", vt->v_part[i].p_size);
DPRINTF1("\t tag %d", vt->v_part[i].p_tag);
DPRINTF1("\t flag %d", vt->v_part[i].p_flag);
}
}
#endif
return (0);
}
#define SWAP(a, b) {diskaddr_t tmp; tmp = (a); (a) = (b); (b) = tmp; }
static int32_t
check_vtoc_sanity(smedia_handle_t handle, int32_t fd, struct extvtoc *vt)
{
int32_t i, j;
struct dk_geom dkg;
int32_t num_backup = 0;
diskaddr_t backup_size = 0;
struct part_struct {
diskaddr_t start;
diskaddr_t end;
int32_t num;
} part[NDKMAP];
diskaddr_t min_val;
int32_t min_slice, num_slices;
diskaddr_t media_size;
uint32_t cyl_size;
int sparc_style = 0;
struct fdisk_info fdisk;
int sol_part;
int total_parts = 0;
#ifdef sparc
sparc_style = 1;
#endif
if ((med_info.sm_media_type == SM_FLOPPY) ||
(med_info.sm_media_type == SM_PCMCIA_MEM) ||
(med_info.sm_media_type == SM_PCMCIA_ATA) ||
(med_info.sm_media_type == SM_SCSI_FLOPPY)) {
sparc_style = 1;
}
if (sparc_style) {
DPRINTF("sparc style true\n");
if (ioctl(fd, DKIOCGGEOM, &dkg) < 0) {
PERROR("DKIOCGGEOM Failed");
return (-1);
}
media_size = (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
dkg.dkg_nsect;
cyl_size = dkg.dkg_nhead * dkg.dkg_nsect;
}
if (!sparc_style) {
if (get_fdisk(handle, fd, 0, &fdisk) >= 0) {
sol_part = 0xFF;
for (i = 0; i < FD_NUMPART; i++) {
if (fdisk.part[i].systid == SUNIXOS ||
fdisk.part[i].systid == SUNIXOS2) {
if (sol_part == 0xFF)
sol_part = i;
total_parts++;
if (fdisk.part[i].bootid == ACTIVE)
sol_part = i;
}
}
if (sol_part == 0xFF) {
(void) fprintf(stderr, gettext("No FDISK \
Solaris partition found!\n"));
return (-1);
}
if (total_parts > 1)
(void) fprintf(stderr, gettext("Multiple FDISK \
Solaris partitions found.\n"));
media_size = (diskaddr_t)fdisk.part[sol_part].numsect;
DPRINTF1("sol_part %d\n", sol_part);
DPRINTF1("media_size %llu\n", media_size);
} else {
DPRINTF("Didn't get fdisk\n");
if (ioctl(fd, DKIOCGGEOM, &dkg) < 0)
if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) {
DPRINTF("DKIOCG_PHYGEOM ioctl failed");
return (-1);
}
dkg.dkg_ncyl = dkg.dkg_ncyl - 1;
media_size = (diskaddr_t)dkg.dkg_ncyl * dkg.dkg_nhead *
dkg.dkg_nsect;
}
}
#ifdef DEBUG
DPRINTF1("Ncyl %d\n", dkg.dkg_ncyl);
DPRINTF1("nhead %d\n", dkg.dkg_nhead);
DPRINTF1("nsect %d\n", dkg.dkg_nsect);
#endif
if (media_size == 0) {
media_size = (uint32_t)med_info.sm_capacity;
}
(void) memset(&part, 0, sizeof (part));
for (i = 0, j = 0; i < NDKMAP; i++) {
if (vt->v_part[i].p_tag == V_BACKUP) {
if (vt->v_part[i].p_start != 0) {
(void) fprintf(stderr,
gettext(
"Backup slice should start at sector 0\n"));
return (-1);
}
backup_size = vt->v_part[i].p_size;
num_backup++;
continue;
}
if (vt->v_part[i].p_size) {
if (sparc_style) {
if (vt->v_part[i].p_start % cyl_size) {
(void) fprintf(stderr,
gettext(
"Slice %d does not start on cylinder boundary\n"), i);
(void) fprintf(stderr,
gettext(
"Cylinder size %d 512 byte sectors\n"), cyl_size);
return (-1);
}
}
part[j].start = vt->v_part[i].p_start;
part[j].end = vt->v_part[i].p_start +
vt->v_part[i].p_size -1;
part[j].num = i;
j++;
}
}
if (num_backup > 1) {
(void) fprintf(stderr,
gettext("Maximum one backup slice is allowed\n"));
(void) smedia_release_handle(handle);
(void) close(fd);
exit(1);
}
num_slices = j;
for (i = 0; i < num_slices; i++) {
min_val = part[i].start;
min_slice = i;
for (j = i+1; j < num_slices; j++) {
if (part[j].start < min_val) {
min_val = part[j].start;
min_slice = j;
}
}
if (min_slice != i) {
SWAP(part[i].start, part[min_slice].start)
SWAP(part[i].end, part[min_slice].end)
SWAP(part[i].num, part[min_slice].num)
}
}
#ifdef DEBUG
for (i = 0; i < num_slices; i++) {
DPRINTF4("\n %d (%d) : %llu, %llu", i, part[i].num,
part[i].start, part[i].end);
}
#endif
if (backup_size > media_size) {
if (sparc_style) {
(void) fprintf(stderr,
gettext(
"Backup slice extends beyond size of media\n"));
(void) fprintf(stderr,
gettext("media size : %llu sectors \n"),
media_size);
} else {
(void) fprintf(stderr,
gettext("Backup slice extends beyond size of FDISK \
Solaris partition\n"));
(void) fprintf(stderr,
gettext(
"FDISK Solaris partition size : %llu sectors \n"),
media_size);
}
return (-1);
}
if (num_slices == 0)
return (0);
if (backup_size) {
if (part[num_slices - 1].end > backup_size) {
(void) fprintf(stderr,
gettext("Slice %d extends beyond backup slice.\n"),
part[num_slices -1].num);
return (-1);
}
} else {
if (part[num_slices - 1].end > media_size) {
if (sparc_style) {
(void) fprintf(stderr,
gettext(
"Slice %d extends beyond media size\n"),
part[num_slices -1].num);
(void) fprintf(stderr,
gettext("media size : %llu sectors \n"),
media_size);
} else {
(void) fprintf(stderr,
gettext("Slice %d extends beyond FDISK"
" Solaris partition size\n"),
part[num_slices -1].num);
(void) fprintf(stderr, gettext(
"FDISK Solaris partition size : %llu "
"sectors \n"), media_size);
}
return (-1);
}
}
for (i = 0; i < num_slices; i++) {
if (i == 0)
continue;
if (part[i].start <= part[i-1].end) {
(void) fprintf(stderr,
gettext("Overlap between slices %d and %d\n"),
part[i-1].num, part[i].num);
(void) smedia_release_handle(handle);
(void) close(fd);
exit(1);
}
}
return (0);
}
static int32_t
get_fdisk(smedia_handle_t handle, int32_t fd, int32_t offset,
struct fdisk_info *fdisk)
{
struct mboot *boot_sec;
struct ipart *part;
char *buf;
int32_t i, ret;
int save_errno;
buf = (char *)malloc(med_info.sm_blocksize);
if (buf == NULL) {
PERROR("malloc failed");
exit(1);
}
errno = 0;
ret = ioctl(fd, DKIOCGMBOOT, buf);
if (ret < 0) {
if (errno != ENOTTY) {
PERROR("DKIOCGMBOOT ioctl failed");
return (-1);
}
(void) __priv_bracket(PRIV_ON);
ret = smedia_raw_read(handle,
(diskaddr_t)offset/med_info.sm_blocksize,
buf, med_info.sm_blocksize);
(void) __priv_bracket(PRIV_OFF);
save_errno = errno;
errno = save_errno;
if (ret != med_info.sm_blocksize) {
if (errno == ENOTSUP) {
errno = 0;
if (lseek(fd, offset, SEEK_SET)) {
PERROR("Seek failed:");
free(buf);
return (-1);
}
(void) __priv_bracket(PRIV_ON);
ret = read(fd, buf, sizeof (struct mboot));
(void) __priv_bracket(PRIV_OFF);
if (ret != sizeof (struct mboot)) {
PERROR("Could not read "
"master boot record");
free(buf);
return (-1);
}
} else {
PERROR("Could not read master boot record");
free(buf);
return (-1);
}
}
}
boot_sec = (struct mboot *)buf;
if (les(boot_sec->signature) != MBB_MAGIC) {
DPRINTF("fdisk: Invalid master boot file \n");
DPRINTF2("Bad magic number: is %x, should be %x.\n",
les(boot_sec->signature), MBB_MAGIC);
free(buf);
return (-1);
}
for (i = 0; i < FD_NUMPART; i++) {
DPRINTF1("part %d\n", i);
part = (struct ipart *)&boot_sec->parts[i *
sizeof (struct ipart)];
fdisk->part[i].bootid = part->bootid;
if (part->bootid && (part->bootid != ACTIVE)) {
return (-1);
}
fdisk->part[i].systid = part->systid;
fdisk->part[i].relsect = lel(GET_32(&(part->relsect)));
fdisk->part[i].numsect = lel(GET_32(&(part->numsect)));
DPRINTF1("\tboot id 0x%x\n", part->bootid);
DPRINTF1("\tsystem id 0x%x\n", part->systid);
DPRINTF1("\trel sector 0x%x\n", fdisk->part[i].relsect);
DPRINTF1("\tnum sector 0x%x\n", fdisk->part[i].numsect);
}
free(buf);
return (0);
}
#ifdef sparc
void
write_default_label(smedia_handle_t handle, int32_t fd)
{
struct extvtoc v_toc;
uint32_t nhead, numcyl, nsect;
diskaddr_t capacity;
int32_t ret;
char asciilabel[LEN_DKL_ASCII];
char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0";
uint32_t acyl = 2;
DPRINTF("Writing default vtoc\n");
(void) memset(&v_toc, 0, sizeof (v_toc));
v_toc.v_nparts = V_NUMPAR;
v_toc.v_sanity = VTOC_SANE;
v_toc.v_version = V_VERSION;
v_toc.v_sectorsz = DEV_BSIZE;
if ((uint32_t)med_info.sm_capacity <= 0x200000) {
nhead = 64;
nsect = 32;
} else {
nhead = 255;
nsect = 63;
}
numcyl = (uint32_t)med_info.sm_capacity / (nhead * nsect);
capacity = (diskaddr_t)nhead * nsect * numcyl;
v_toc.v_part[0].p_start = 0;
v_toc.v_part[0].p_size = capacity;
v_toc.v_part[0].p_tag = V_ROOT;
v_toc.v_part[0].p_flag = 0;
v_toc.v_part[2].p_start = 0;
v_toc.v_part[2].p_size = capacity;
v_toc.v_part[2].p_tag = V_BACKUP;
v_toc.v_part[2].p_flag = V_UNMNT;
(void) snprintf(asciilabel, sizeof (asciilabel),
"%s cyl %d alt %d hd %d sec %d",
asciilabel2, numcyl, acyl, nhead, nsect);
(void) memcpy(v_toc.v_asciilabel, asciilabel,
LEN_DKL_ASCII);
errno = 0;
(void) __priv_bracket(PRIV_ON);
ret = write_extvtoc(fd, &v_toc);
(void) __priv_bracket(PRIV_OFF);
if (ret < 0) {
PERROR("write VTOC failed");
DPRINTF1("Errno = %d\n", errno);
}
}
#else
#ifdef i386
void
write_default_label(smedia_handle_t handle, int32_t fd)
{
int32_t i, ret;
struct dk_geom dkg;
struct extvtoc v_toc;
int tmp_fd;
char *fdisk_buf;
struct mboot boot_code;
struct ipart parts[FD_NUMPART];
uint32_t numcyl, nhead, nsect;
uint32_t unixend;
uint32_t blocksize;
diskaddr_t capacity;
int save_errno;
size_t bytes_written;
char asciilabel[LEN_DKL_ASCII];
char asciilabel2[LEN_DKL_ASCII] = "DEFAULT\0";
uint32_t acyl = 2;
DPRINTF("Writing default fdisk table and vtoc\n");
(void) memset(&v_toc, 0, sizeof (v_toc));
if (ioctl(fd, DKIOCGGEOM, &dkg) < 0)
if (ioctl(fd, DKIOCG_PHYGEOM, &dkg) < 0) {
DPRINTF("DKIOCG_PHYGEOM ioctl failed");
return;
}
tmp_fd = open("/boot/pmbr", O_RDONLY);
if (tmp_fd <= 0) {
return;
}
if (read(tmp_fd, &boot_code, sizeof (struct mboot))
!= sizeof (struct mboot)) {
(void) close(tmp_fd);
return;
}
blocksize = med_info.sm_blocksize;
fdisk_buf = (char *)malloc(blocksize);
if (fdisk_buf == NULL) {
DPRINTF("malloc for fdisk_buf failed\n");
return;
}
(void) memset(&parts, 0, sizeof (parts));
for (i = 0; i < FD_NUMPART; i++) {
parts[i].systid = UNUSED;
parts[i].numsect = lel(UNUSED);
parts[i].relsect = lel(UNUSED);
parts[i].bootid = 0;
}
numcyl = dkg.dkg_ncyl;
nhead = dkg.dkg_nhead;
nsect = dkg.dkg_nsect;
parts[0].bootid = ACTIVE;
parts[0].begsect = 1;
unixend = numcyl;
parts[0].relsect = lel(nhead * nsect);
parts[0].numsect = lel(((diskaddr_t)numcyl * nhead * nsect));
parts[0].systid = SUNIXOS2;
parts[0].beghead = 0;
parts[0].begcyl = 1;
parts[0].endhead = nhead - 1;
parts[0].endsect = (nsect & 0x3f) |
(char)((unixend >> 2) & 0x00c0);
parts[0].endcyl = (char)(unixend & 0x00ff);
(void) memcpy(&(boot_code.parts), parts, sizeof (parts));
(void) memcpy(fdisk_buf, &boot_code, sizeof (boot_code));
(void) __priv_bracket(PRIV_ON);
ret = ioctl(fd, DKIOCSMBOOT, fdisk_buf);
(void) __priv_bracket(PRIV_OFF);
if (ret == -1) {
if (errno != ENOTTY) {
PERROR("DKIOCSMBOOT ioctl Failed");
return;
}
(void) __priv_bracket(PRIV_ON);
bytes_written = smedia_raw_write(handle, (diskaddr_t)0,
fdisk_buf, blocksize);
(void) __priv_bracket(PRIV_OFF);
save_errno = errno;
errno = save_errno;
if (bytes_written != blocksize) {
if (errno == ENOTSUP) {
(void) __priv_bracket(PRIV_ON);
ret = write(fd, fdisk_buf, blocksize);
(void) __priv_bracket(PRIV_OFF);
if (ret != blocksize) {
return;
}
} else {
return;
}
}
}
capacity = (diskaddr_t)(numcyl - 1) * nhead * nsect;
v_toc.v_nparts = V_NUMPAR;
v_toc.v_sanity = VTOC_SANE;
v_toc.v_version = V_VERSION;
v_toc.v_sectorsz = DEV_BSIZE;
v_toc.v_part[0].p_start = 0;
v_toc.v_part[0].p_size = capacity;
v_toc.v_part[0].p_tag = V_ROOT;
v_toc.v_part[0].p_flag = 0;
v_toc.v_part[2].p_start = 0;
v_toc.v_part[2].p_size = capacity;
v_toc.v_part[2].p_tag = V_BACKUP;
v_toc.v_part[2].p_flag = V_UNMNT;
(void) snprintf(asciilabel, sizeof (asciilabel),
"%s cyl %d alt %d hd %d sec %d",
asciilabel2, numcyl, acyl, nhead, nsect);
(void) memcpy(v_toc.v_asciilabel, asciilabel,
LEN_DKL_ASCII);
errno = 0;
(void) __priv_bracket(PRIV_ON);
ret = write_extvtoc(fd, &v_toc);
(void) __priv_bracket(PRIV_OFF);
if (ret < 0) {
PERROR("write VTOC failed");
DPRINTF1("Errno = %d\n", errno);
}
}
#else
#error One of sparc or i386 must be defined!
#endif
#endif
void
overwrite_metadata(int32_t fd, smedia_handle_t handle)
{
struct fdisk_info fdisk;
diskaddr_t sol_offset = 0;
int i, ret;
struct extvtoc t_vtoc;
#ifdef i386
diskaddr_t sol_size = 0;
int32_t active = 0;
#endif
if (get_fdisk(handle, fd, 0, &fdisk) >= 0) {
for (i = 0; i < FD_NUMPART; i++) {
if (fdisk.part[i].numsect == 0)
continue;
if ((fdisk.part[i].systid == UNUSED) ||
(fdisk.part[i].systid == 0))
continue;
#ifdef i386
if (fdisk.part[i].systid == SUNIXOS ||
fdisk.part[i].systid == SUNIXOS2) {
if (!sol_offset) {
sol_offset = fdisk.part[i].relsect;
sol_size = fdisk.part[i].numsect;
if (fdisk.part[i].bootid == ACTIVE)
active = 1;
continue;
} else if ((fdisk.part[i].bootid == ACTIVE) &&
(!active)) {
erase(handle, sol_offset, sol_size);
sol_offset = fdisk.part[i].relsect;
sol_size = fdisk.part[i].numsect;
active = 1;
continue;
}
}
#endif
erase(handle, (diskaddr_t)fdisk.part[i].relsect,
(diskaddr_t)fdisk.part[i].numsect);
}
}
(void) memset(&t_vtoc, 0, sizeof (t_vtoc));
if (sol_offset) {
(void) __priv_bracket(PRIV_ON);
ret = read_extvtoc(fd, &t_vtoc);
(void) __priv_bracket(PRIV_OFF);
if (ret < 0) {
erase(handle, (diskaddr_t)0, (diskaddr_t)1);
return;
}
} else {
(void) __priv_bracket(PRIV_ON);
ret = read_extvtoc(fd, &t_vtoc);
(void) __priv_bracket(PRIV_OFF);
if (ret < 0) {
erase(handle, (diskaddr_t)0,
(uint32_t)med_info.sm_capacity);
return;
}
}
for (i = 0; i < V_NUMPAR; i++) {
if (t_vtoc.v_part[i].p_size != 0) {
erase(handle, sol_offset + t_vtoc.v_part[i].p_start,
t_vtoc.v_part[i].p_size);
erase(handle,
sol_offset + t_vtoc.v_part[i].p_start + 256,
(diskaddr_t)1);
erase(handle,
(sol_offset + t_vtoc.v_part[i].p_start +
t_vtoc.v_part[i].p_size - 256),
(diskaddr_t)1);
erase(handle,
(sol_offset + t_vtoc.v_part[i].p_start +
t_vtoc.v_part[i].p_size - 1),
(diskaddr_t)1);
}
}
if (sol_offset) {
erase(handle, sol_offset, (diskaddr_t)DK_LABEL_LOC + 2);
}
erase(handle, (diskaddr_t)0, (diskaddr_t)1);
}
static void
erase(smedia_handle_t handle, diskaddr_t offset, diskaddr_t size)
{
char *buf;
diskaddr_t nblocks = size;
int32_t ret;
nblocks = (nblocks < 128) ? nblocks : 128;
buf = (char *)malloc(nblocks * med_info.sm_blocksize);
if (buf == NULL) {
PERROR("malloc failed");
return;
}
(void) memset(buf, 0, (size_t)nblocks * med_info.sm_blocksize);
(void) __priv_bracket(PRIV_ON);
ret = smedia_raw_write(handle, offset, buf,
(size_t)nblocks * med_info.sm_blocksize);
(void) __priv_bracket(PRIV_OFF);
if (ret != (nblocks * med_info.sm_blocksize))
PERROR("error in writing\n");
free(buf);
}