rmf_slice.c revision e33975576e182867dfb0d525ecf5ef51154047f9
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* rmf_slice.c :
* This file contains the functions for parsing a slice file
* for rmformat.
*/
#include <ctype.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
#include <memory.h>
#include <dirent.h>
#include <stdio.h>
#include <priv.h>
#include "rmformat.h"
extern void my_perror(char *err_string);
static int32_t last_token_type = 0;
#define spc() (last_token_type)
/*
* This global is used to store the current line # in the
* data file. It must be global because the I/O routines
* are allowed to side effect it to keep track of backslashed
* newlines.
*/
#define CHG_MODE_SET 0 /* set bits by or'ing */
#define DATA_INPUT 0 /* 2 modes of input */
#define CMD_INPUT 1
/*
* List of strings with arbitrary matching values
*/
typedef struct slist {
char *str;
char *help;
} slist_t;
static slist_t ptag_choices[] = {
{ NULL }
};
/*
* Choices for the p_flag vtoc field
*/
static slist_t pflag_choices[] = {
{ "wm", "read-write, mountable", 0 },
{ NULL }
};
/*
* The definitions are the token types that the data file parser recognizes.
*/
#define SUP_STRING 0 /* string token */
/*
* Prototypes for ANSI C compilers
*/
static void sup_pushchar(int32_t c);
static int32_t sup_inputchar();
struct fdisk_info *fdisk);
extern char *myname;
extern smmedium_prop_t med_info;
static int32_t
{
/*
* Open the data file. Return 0 if unable to do so.
*/
PERROR("Open failed");
return (-1);
}
/*
* Step through the data file a meta-line at a time. There are
* typically several backslashed newlines in each meta-line,
* so data_lineno will be getting side effected along the way.
*/
data_lineno = 1;
for (;;) {
/*
* Get the keyword.
*/
/*
* If we hit the end of the data file, we're done.
*/
break;
/*
* If the line starts with some key character, it's an error.
*/
if (status != SUP_STRING) {
gettext("Expecting keyword, found '%s'"),
token);
continue;
}
/*
* Clean up the token and see which keyword it is. Call
* the appropriate routine to process the rest of the line.
*/
return (ret_val);
} else {
cleaned);
return (-1);
}
}
/*
* Close the data file.
*/
return (-1);
}
static int32_t
sup_gettoken(char *buf)
{
/*
* Skip end of lines and blank lines.
*/
;
return (last_token_type);
}
static int32_t
sup_get_token(char *buf)
{
/*
* Was an end of file detected last try?
*/
return (SUP_EOF);
}
/*
* Zero out the returned token buffer
*/
/*
* Strip off leading white-space.
*/
while (isspace(c = sup_inputchar()))
;
/*
* Only white spaces and then end of file?
*/
return (SUP_EOF);
}
/*
* Read in characters until we hit unquoted white-space.
*/
/*
* If we hit eof, check if we have anything in buffer.
* if we have, return STRING, next time we will return EOF
* else, return EOF here...should not happen.
*/
return (SUP_STRING);
} else {
return (SUP_EOF);
}
}
/*
* If we hit a double quote, change the state of quoting.
*/
if (c == '"') {
continue;
}
/*
* If we hit a newline, that delimits a token.
*/
if (c == '\n')
break;
/*
* If we hit any nonquoted special delimiters, that delimits
* a token.
*/
c == '#' || c == '|' || c == '&' || c == '~'))
break;
/*
* Store the character if there's room left.
*/
*ptr++ = (char)c;
}
/*
* If we stored characters in the buffer, then we inputted a string.
* Push the delimiter back into the pipe and return the string.
*/
sup_pushchar(c);
return (SUP_STRING);
}
/*
* We didn't input a string, so we must have inputted a known delimiter.
* store the delimiter in the buffer, so it will get returned.
*/
buf[0] = c;
/*
* Switch on the delimiter. Return the appropriate value for each one.
*/
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 '#':
/*
* For comments, we flush out the rest of the line and return
* an eol.
*/
;
return (SUP_EOF);
else
return (SUP_EOL);
/*
* Shouldn't ever get here.
*/
default:
return (SUP_STRING);
}
}
static int32_t
{
int32_t c;
/*
* Input the character.
*/
/*
* If it's not a backslash, return it.
*/
/*
* It was a backslash. Get the next character.
*/
if (c == '\\')
/*
* If it was a newline, update the line counter and get the next
* character.
*/
if (c == '\n') {
data_lineno++;
}
/*
* Return the character.
*/
return (c);
}
static void
{
if (c == '\n')
data_lineno--;
}
static void
{
char *ptr;
/*
* Strip off leading white-space.
*/
/*
* Copy it into the clean buffer.
*/
/*
* Strip off trailing white-space.
*/
*ptr = '\0';
}
}
static int32_t
{
/*
* Pull in some grammar.
*/
return (-1);
}
for (;;) {
if (status != SUP_STRING) {
return (-1);
}
clean_token(ident, token);
/*
* Also make sure it is within the legal range of letters.
*/
/*
* Here's the index of the partition we're dealing with
*/
return (-1);
}
/*
* Check for floppy and PCMCIA_MEM cards.
* for floppy, the partition no. can be 0 1 2.
* for PCMCIA, the partition no. can be 2
*/
"Floppy can have partitions 0 1 and 2\n"));
return (-1);
}
}
if (index != 2) {
"PCMCIA Memory cards can have partition 2 only.\n"));
return (-1);
}
}
return (-1);
}
/*
* If we hit a key character, it's an error.
*/
if (status != SUP_STRING) {
return (-1);
}
/*
* <tag> may be one of: boot, root, swap, etc.
* <flag> consists of two characters:
* W (writable) or R (read-only)
* M (mountable) or U (unmountable)
*
* Start with the defaults assigned above:
*/
/*
* All other attributes have a pair of numeric values.
* Convert the first value to a number. This value
* is the starting cylinder number of the partition.
*/
/* Check for valid partition, e.g. > 8 or 16 */
if (val1 == -1) {
gettext("Invalid partition beggining %s \n"),
cleaned);
}
/*
* Pull in some grammar.
*/
return (-1);
}
/*
* Pull in the second value.
*/
if (status != SUP_STRING) {
return (-1);
}
if (val2 == -1) {
gettext("Invalid partition size %s \n"),
cleaned);
}
/*
* Pull in some grammar.
*/
/* tags and flags */
if (status != SUP_STRING) {
gettext("Expecting value, found '%s'"),
token);
return (-1);
}
/*
* Found valid tag. Use it and advance parser
*/
gettext("Expecting : got %s\n"),
token);
gettext("Line no %d\n"),
return (-1);
}
} else {
gettext("Invalid flag or tag\n"));
return (-1);
}
/* Can be tag only */
if (status != SUP_STRING) {
"Expecting value, found '%s'"),
token);
gettext("Line no %d\n"),
return (-1);
}
if (find_value(ptag_choices,
cleaned, &i) == 1) {
}
}
}
/*
* Fill in the appropriate map entry with the values.
*/
if (vtoc_tag != 0xFFFF) {
vtoc_tag = 0xFFFF;
}
if (vtoc_flag != 0xFFFF) {
vtoc_flag = 0xFFFF;
}
DPRINTF("\nEnd of file\n");
break;
}
return (-1);
}
}
return (0);
}
static int32_t
{
int32_t i;
nmatches = 0;
length = 0;
/*
* See how many characters of the token match
*/
/*
* If it's not the whole token, then it's not a match.
*/
if (i < match_length) {
continue;
}
/*
* If it ties with another input, remember that.
*/
if (i == length)
nmatches++;
/*
* If it matches the most so far, record that.
*/
if (i > length) {
nmatches = 1;
length = i;
}
}
return (nmatches);
}
static int32_t
{
int32_t i = 0;
i++;
return (i);
}
static int32_t
str2sector(char *str)
{
PERROR("Malloc failed");
return (-1);
}
*s2 = '\0';
while (*s1) {
(*s1 > '9'))) {
if (*s1 == 'G') {
s1++;
} else if (*s1 == 'M') {
s1++;
} else if (*s1 == 'K') {
mul_factor = 1024;
s1++;
}
gettext("Extra chars at the end\n"));
return (-1);
}
break;
} else {
*s2 = '\0';
}
}
return (-1);
}
return (num_sectors);
}
{
return (-1);
}
/* Set default tag and flag */
#ifdef sparc
#endif
if (ret_val < 0)
return (-1);
#ifdef DEBUG
{
int32_t i;
for (i = 0; i < 8; i++) {
DPRINTF1("\npart %d\n", i);
}
}
#endif /* DEBUG */
return (-1);
}
#ifdef DEBUG
{
int32_t i;
for (i = 0; i < 8; i++) {
DPRINTF1("\npart %d\n", i);
}
}
#endif /* DEBUG */
return (0);
}
/*
* On x86 Solaris, the partitioning is done in two levels, fdisk and Solaris
* VTOC. Where as, on sparc solaris, it is only VTOC. On floppy and PCMCIA
* also it is assumed to be only VTOC, no fdisk.
*
* On sparc, the back up slice can cover the whole medium. But on x86
* in fdisk table.
* Following table describes how is it handled
* SPARC:
* DKIOCGGEOM is sufficient.
* x86 : floppy, pcmcia : Don't check for fdisk. DKIOCGGEOM is sufficient.
* if not present, assume that the solaris
* partition covers 100% of the medium
* (minus one cylinder).
*
* if present :
* check for active solaris partition.
* if not found, take the first solaris
* partition.
* If there are no solaris partitions, its an error, stop.
*/
static int32_t
{
int32_t i, j;
int32_t num_backup = 0;
long backup_size = 0;
struct part_struct {
long start;
long end;
long media_size;
int sparc_style = 0; /* sparc_style handling ? */
struct fdisk_info fdisk;
int sol_part;
int total_parts = 0;
#ifdef sparc
sparc_style = 1;
#endif /* sparc */
sparc_style = 1;
}
if (sparc_style) {
DPRINTF("sparc style true\n");
PERROR("DKIOCGGEOM Failed");
return (-1);
}
}
if (!sparc_style) {
/*
* Try to get the fdisk information if available.
*/
/* fdisk table on disk */
sol_part = 0xFF;
for (i = 0; i < FD_NUMPART; i++) {
if (sol_part == 0xFF)
sol_part = i;
total_parts++;
sol_part = i;
}
}
if (sol_part == 0xFF) {
/* No Solaris partition */
Solaris partition found!\n"));
return (-1);
}
if (total_parts > 1)
Solaris partitions found.\n"));
} else {
DPRINTF("Didn't get fdisk\n");
/*
* No fdisk partition available. Assume a 100% Solaris.
* partition.
* Try getting disk geometry.
*/
DPRINTF("DKIOCG_PHYGEOM ioctl failed");
return (-1);
}
/* On x86 platform 1 cylinder is used for fdisk table */
}
}
#ifdef DEBUG
#endif /* DEBUG */
if (media_size == 0) {
}
for (i = 0, j = 0; i < NDKMAP; i++) {
"Backup slice should start at sector 0\n"));
return (-1);
}
num_backup++;
continue;
}
if (sparc_style) {
"Slice %d does not start on cylinder boundary\n"), i);
"Cylinder size %d 512 byte sectors\n"), cyl_size);
return (-1);
}
}
j++;
}
}
if (num_backup > 1) {
gettext("Maximum one backup slice is allowed\n"));
(void) smedia_release_handle(handle);
exit(1);
}
num_slices = j;
for (i = 0; i < num_slices; i++) {
min_slice = i;
for (j = i+1; j < num_slices; j++) {
min_slice = j;
}
}
if (min_slice != i) {
}
}
#ifdef DEBUG
for (i = 0; i < num_slices; i++) {
}
#endif /* DEBUG */
if (backup_size > media_size) {
if (sparc_style) {
"Backup slice extends beyond size of media\n"));
} else {
gettext("Backup slice extends beyond size of FDISK \
Solaris partition\n"));
"FDISK Solaris partition size : %d sectors \n"),
}
return (-1);
}
/*
* If we have only backup slice return success here.
*/
if (num_slices == 0)
return (0);
if (backup_size) {
gettext("Slice %d extends beyond backup slice.\n"),
return (-1);
}
} else {
if (sparc_style) {
"Slice %d extends beyond media size\n"),
gettext("media size : %d sectors \n"),
} else {
"Slice %d extends beyond FDISK Solaris partition size\n"),
gettext("FDISK Solaris partition size : %d \
sectors \n"), media_size);
}
return (-1);
}
}
for (i = 0; i < num_slices; i++) {
if (i == 0)
continue;
gettext("Overlap between slices %d and %d\n"),
(void) smedia_release_handle(handle);
exit(1);
}
}
return (0);
}
static int32_t
struct fdisk_info *fdisk)
{
char *buf;
int save_errno;
/* Read the master boot program */
PERROR("malloc failed");
exit(1);
}
errno = 0;
if (ret < 0) {
PERROR("DKIOCGMBOOT ioctl failed");
return (-1);
}
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
save_errno = errno;
errno = save_errno;
errno = 0;
PERROR("Seek failed:");
return (-1);
}
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
PERROR("Could not read master boot record");
return (-1);
}
} else {
PERROR("Could not read master boot record");
return (-1);
}
}
}
/* LINTED pointer cast may result in improper alignment */
/* Is this really a master boot record? */
DPRINTF("fdisk: Invalid master boot file \n");
DPRINTF2("Bad magic number: is %x, should be %x.\n",
return (-1);
}
for (i = 0; i < FD_NUMPART; i++) {
DPRINTF1("part %d\n", i);
/* LINTED pointer cast may result in improper alignment */
sizeof (struct ipart)];
/* Hmmm...not a valid fdisk! */
return (-1);
}
/* To avoid the misalign access in sparc */
}
return (0);
}
/*
* wrrite_defualt_label(int32_t fd)
* fd = file descriptor for the device.
*
* For sparc solaris
* Create a vtoc partition with
* slice 0 = slice 2 = medium capacity.
* The cyl, head, sect (CHS) values are computed as done in sd
* capacity <= 1GB,
* nhead = 64, nsect = 32
* capacity > 1gb,
* nhead = 255, nsect = 63
*
* For x86 solaris
* Create a fdisk partition,
* partition 0 covers the full medium, the partition
* type is set to Solaris.
* Then create solaris vtoc. The algorithm is same as sparc solaris.
* But the capacity is reduced by 1 cyl, to leave space for fdisk table.
*/
#ifdef sparc
/*ARGSUSED*/
void
{
char asciilabel[LEN_DKL_ASCII];
DPRINTF("Writing default vtoc\n");
/*
* For the head, cyl and number of sector per track,
* if the capacity <= 1GB, head = 64, sect = 32.
* else head = 255, sect 63
* NOTE: the capacity should be equal to C*H*S values.
* This will cause some truncation of size due to
* round off errors.
*/
nhead = 64;
nsect = 32;
} else {
nhead = 255;
nsect = 63;
}
/* Create asciilabel for compatibility with format utility */
"%s cyl %d alt %d hd %d sec %d",
errno = 0;
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
if (ret < 0) {
PERROR("write VTOC failed");
}
}
#else /* !sparc */
#ifdef i386
void
{
int tmp_fd;
char *fdisk_buf;
int save_errno;
char asciilabel[LEN_DKL_ASCII];
DPRINTF("Writing default fdisk table and vtoc\n");
/*
* Try getting disk geometry.
*/
DPRINTF("DKIOCG_PHYGEOM ioctl failed");
return;
}
if (tmp_fd <= 0) {
return;
}
!= sizeof (struct mboot)) {
return;
}
DPRINTF("malloc for fdisk_buf failed\n");
return;
}
for (i = 0; i < FD_NUMPART; i++) {
}
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
if (ret == -1) {
PERROR("DKIOCSMBOOT ioctl Failed");
return;
}
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
save_errno = errno;
errno = save_errno;
if (bytes_written != blocksize) {
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
return;
}
} else {
return;
}
}
}
/* Create asciilabel for compatibility with format utility */
"%s cyl %d alt %d hd %d sec %d",
errno = 0;
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
if (ret < 0) {
PERROR("write VTOC failed");
}
}
#else /* !i386 */
#endif /* i386 */
#endif /* sparc */
/*
* void overwrite_metadata(int32_t fd, smedia_handle_t handle)
*
* purpose : quick format does not erase the data on Iomega
*
* If there is a valid fdisk table,
* erase first 64K of each partition.
* If there is a valid vtoc,
* erase first 64k of each slice.
* Then erase the 0th sector (the home for vtoc and fdisk) of the disk.
* Note that teh vtoc on x86 resides in one of the fdisk partition.
* So delay the erasing of the solaris partition until the vtoc is read.
*/
void
{
struct fdisk_info fdisk;
uint32_t sol_offset = 0;
int i, ret;
#ifdef i386
#endif /* i386 */
/* Get fdisk info. */
/* Got a valid fdisk */
for (i = 0; i < FD_NUMPART; i++) {
continue;
continue;
#ifdef i386
if (!sol_offset) {
active = 1;
continue;
(!active)) {
active = 1;
continue;
}
}
#endif /* i386 */
}
}
if (sol_offset) {
/* fdisk x86 Solaris partition */
/* VTOC location in solaris partition is DK_LABEL_LOC */
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_brackets(PRIV_OFF);
if (ret < 0) {
/* No valid vtoc, erase fdisk table. */
return;
}
} else {
/* Sparc Solaris or x86 solaris with faked fdisk */
/* Turn on privileges */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
if (ret < 0) {
/* No valid vtoc, erase from 0th sector */
return;
}
}
for (i = 0; i < V_NUMPAR; i++) {
/*
* To make the udfs not recognise the partition we will
* erase sectors 256, (p_size-256) and psize.
*/
1);
1);
1);
}
}
/*
* If x86 fdisk solaris partition, erase the vtoc also.
* for sparc, the erasing 0the sector erases vtoc.
*/
if (sol_offset) {
}
/*
* erase the 0th sector, it is not guaranteed to be
* erased in the above sequence.
*/
}
/*
* void erase(smedia_handle_t handle, uint32_t offset, uint32_t size)
*
* Initialize the media with '0' from offset 'offset' upto 'size'
* or 128 blocks(64k), whichever is smaller.
*/
static void
{
char *buf;
PERROR("malloc failed");
return;
}
/* Turn on privileges. */
(void) __priv_bracket(PRIV_ON);
/* Turn off privileges. */
(void) __priv_bracket(PRIV_OFF);
PERROR("error in writing\n");
}