2006-03-18 14:38:59 +03:00
|
|
|
/* $NetBSD: main.c,v 1.9 2006/03/18 11:38:59 dsl Exp $ */
|
1995-03-18 17:54:19 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
1994-06-24 17:48:17 +04:00
|
|
|
* Copyright (c) 1987, 1993
|
|
|
|
* The Regents of the University of California. All rights reserved.
|
1993-03-21 12:45:37 +03:00
|
|
|
*
|
|
|
|
* This code is derived from software contributed to Berkeley by
|
|
|
|
* Symmetric Computer Systems.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions
|
|
|
|
* are met:
|
|
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer.
|
|
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
|
|
* notice, this list of conditions and the following disclaimer in the
|
|
|
|
* documentation and/or other materials provided with the distribution.
|
2003-08-07 14:04:11 +04:00
|
|
|
* 3. Neither the name of the University nor the names of its contributors
|
1993-03-21 12:45:37 +03:00
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
|
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
|
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
|
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
|
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
|
|
|
* SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
2005-06-12 23:18:34 +04:00
|
|
|
#if HAVE_NBTOOL_CONFIG_H
|
|
|
|
#include "nbtool_config.h"
|
|
|
|
#endif
|
|
|
|
|
1997-07-01 02:51:27 +04:00
|
|
|
#include <sys/cdefs.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
#ifndef lint
|
1997-07-01 02:51:27 +04:00
|
|
|
__COPYRIGHT("@(#) Copyright (c) 1987, 1993\n\
|
|
|
|
The Regents of the University of California. All rights reserved.\n");
|
2000-12-24 08:59:11 +03:00
|
|
|
#endif /* not lint */
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
#ifndef lint
|
1995-03-18 17:54:19 +03:00
|
|
|
#if 0
|
1997-09-16 06:43:59 +04:00
|
|
|
static char sccsid[] = "@(#)disklabel.c 8.4 (Berkeley) 5/4/95";
|
1994-06-24 17:48:17 +04:00
|
|
|
/* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */
|
1995-03-18 17:54:19 +03:00
|
|
|
#else
|
2006-03-18 14:38:59 +03:00
|
|
|
__RCSID("$NetBSD: main.c,v 1.9 2006/03/18 11:38:59 dsl Exp $");
|
1995-03-18 17:54:19 +03:00
|
|
|
#endif
|
2000-12-24 08:59:11 +03:00
|
|
|
#endif /* not lint */
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
#include <sys/param.h>
|
|
|
|
#include <sys/file.h>
|
1994-06-24 17:48:17 +04:00
|
|
|
#include <sys/stat.h>
|
1994-12-05 23:15:31 +03:00
|
|
|
#include <sys/wait.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
#define DKTYPENAMES
|
1998-11-12 19:19:47 +03:00
|
|
|
#define FSTYPENAMES
|
1994-09-30 05:33:15 +03:00
|
|
|
|
|
|
|
#include <ctype.h>
|
1994-09-23 02:03:52 +04:00
|
|
|
#include <err.h>
|
1995-06-27 03:17:26 +04:00
|
|
|
#include <errno.h>
|
1994-06-24 17:48:17 +04:00
|
|
|
#include <unistd.h>
|
1995-06-27 03:17:26 +04:00
|
|
|
#include <signal.h>
|
1994-06-24 17:48:17 +04:00
|
|
|
#include <string.h>
|
1993-03-21 12:45:37 +03:00
|
|
|
#include <stdio.h>
|
1994-09-30 05:33:15 +03:00
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
1997-07-01 02:51:27 +04:00
|
|
|
|
2005-06-12 23:18:34 +04:00
|
|
|
#include <ufs/ufs/dinode.h>
|
|
|
|
#include <ufs/ffs/fs.h>
|
|
|
|
|
|
|
|
#if HAVE_NBTOOL_CONFIG_H
|
|
|
|
#include <nbinclude/sys/disklabel.h>
|
2005-10-20 01:22:21 +04:00
|
|
|
#include <nbinclude/sys/disklabel_acorn.h>
|
2005-06-12 23:18:34 +04:00
|
|
|
#include <nbinclude/sys/bootblock.h>
|
|
|
|
#include "../../include/disktab.h"
|
|
|
|
#else
|
|
|
|
#include <sys/ioctl.h>
|
|
|
|
#include <sys/disklabel.h>
|
2005-10-20 01:22:21 +04:00
|
|
|
#include <sys/disklabel_acorn.h>
|
2005-06-12 23:18:34 +04:00
|
|
|
#include <sys/bootblock.h>
|
|
|
|
#include <util.h>
|
1999-01-19 09:24:08 +03:00
|
|
|
#include <disktab.h>
|
2005-06-12 23:18:34 +04:00
|
|
|
#endif /* HAVE_NBTOOL_CONFIG_H */
|
1999-01-19 09:24:08 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
#include "pathnames.h"
|
1997-03-09 02:46:08 +03:00
|
|
|
#include "extern.h"
|
1997-07-01 02:51:27 +04:00
|
|
|
#include "dkcksum.h"
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Disklabel: read and write disklabels.
|
|
|
|
* The label is usually placed on one of the first sectors of the disk.
|
1994-06-24 17:48:17 +04:00
|
|
|
* Many machines also place a bootstrap in the same area,
|
1993-03-21 12:45:37 +03:00
|
|
|
* in which case the label is embedded in the bootstrap.
|
|
|
|
* The bootstrap source must leave space at the proper offset
|
|
|
|
* for the label on such machines.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#ifndef BBSIZE
|
|
|
|
#define BBSIZE 8192 /* size of boot area, with label */
|
|
|
|
#endif
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
#define DISKMAGIC_REV bswap32(DISKMAGIC)
|
|
|
|
/* To delete a label, we just invert the magic numbers */
|
|
|
|
#define DISKMAGIC_DELETED (~DISKMAGIC)
|
|
|
|
#define DISKMAGIC_DELETED_REV bswap32(~DISKMAGIC)
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
#define DEFEDITOR _PATH_VI
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
char specname[MAXPATHLEN];
|
|
|
|
|
|
|
|
/* Some global data, all too hard to pass about */
|
|
|
|
int bootarea[BBSIZE / sizeof (int)]; /* Buffer matching part of disk */
|
|
|
|
int bootarea_len; /* Number of bytes we actually read */
|
|
|
|
static struct disklabel lab; /* The label we have updated */
|
|
|
|
|
|
|
|
static int Aflag; /* Action all labels */
|
|
|
|
static int Fflag; /* Read/write from file */
|
|
|
|
static int rflag; /* Read/write direct from disk */
|
|
|
|
static int tflag; /* Format output as disktab */
|
|
|
|
int Cflag; /* CHS format output */
|
|
|
|
static int Dflag; /* Delete old labels (use with write) */
|
|
|
|
static int Iflag; /* Read/write direct, but default if absent */
|
|
|
|
static int mflag; /* Expect disk to contain an MBR */
|
|
|
|
static int verbose;
|
|
|
|
static int read_all; /* set if op = READ && Aflag */
|
|
|
|
|
|
|
|
static int write_label(int);
|
|
|
|
static int readlabel_direct(int);
|
|
|
|
static void writelabel_direct(int);
|
|
|
|
static int update_label(int, u_int, u_int);
|
|
|
|
static struct disklabel *find_label(int, u_int);
|
2000-12-24 08:59:11 +03:00
|
|
|
|
|
|
|
static void makedisktab(FILE *, struct disklabel *);
|
2005-10-20 01:22:21 +04:00
|
|
|
static void makelabel(const char *, const char *);
|
2000-12-24 08:59:11 +03:00
|
|
|
static void l_perror(const char *);
|
2005-10-20 01:22:21 +04:00
|
|
|
static void readlabel(int);
|
|
|
|
static int edit(int);
|
|
|
|
static int editit(const char *);
|
2000-12-24 08:59:11 +03:00
|
|
|
static char *skip(char *);
|
|
|
|
static char *word(char *);
|
|
|
|
static int getasciilabel(FILE *, struct disklabel *);
|
|
|
|
static void usage(void);
|
2004-03-14 03:39:53 +03:00
|
|
|
static int getulong(const char *, char, char **,
|
|
|
|
unsigned long *, unsigned long);
|
|
|
|
#define GETNUM32(a, v) getulong(a, '\0', NULL, v, UINT32_MAX)
|
|
|
|
#define GETNUM16(a, v) getulong(a, '\0', NULL, v, UINT16_MAX)
|
|
|
|
#define GETNUM8(a, v) getulong(a, '\0', NULL, v, UINT8_MAX)
|
1994-12-05 23:15:31 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
static int set_writable_fd = -1;
|
|
|
|
|
2005-06-12 23:18:34 +04:00
|
|
|
#if HAVE_NBTOOL_CONFIG_H
|
|
|
|
#define GETLABELOFFSET() LABELOFFSET
|
|
|
|
#define GETLABELSECTOR() LABELSECTOR
|
|
|
|
#else /* HAVE_NBTOOL_CONFIG_H */
|
|
|
|
#define GETLABELOFFSET() getlabeloffset()
|
|
|
|
#define GETLABELSECTOR() getlabelsector()
|
|
|
|
#endif
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
/* Default location for label - only used if we don't find one to update */
|
|
|
|
#define LABEL_OFFSET (GETLABELSECTOR() * DEV_BSIZE + GETLABELOFFSET())
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For portability it doesn't make sense to use any other value....
|
|
|
|
* Except, maybe, the size of a physical sector.
|
|
|
|
* This value is used if we have to write a label to the start of an mbr ptn.
|
|
|
|
*/
|
|
|
|
#ifndef LABELOFFSET_MBR
|
|
|
|
#define LABELOFFSET_MBR 512
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if HAVE_NBTOOL_CONFIG_H
|
|
|
|
static int
|
|
|
|
opendisk(const char *path, int flags, char *buf, int buflen, int cooked)
|
|
|
|
{
|
|
|
|
int f;
|
|
|
|
f = open(path, flags, 0);
|
|
|
|
strlcpy(buf, path, buflen);
|
|
|
|
return f;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
dk_ioctl(int f, void *arg)
|
|
|
|
{
|
|
|
|
errno = ENOTTY;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
#define dk_ioctl(f, cmd, arg) dk_ioctl(f, arg)
|
|
|
|
#else
|
|
|
|
#define dk_ioctl(f, cmd, arg) ioctl(f, cmd, arg)
|
|
|
|
#endif /* HAVE_NBTOOL_CONFIG_H */
|
|
|
|
|
|
|
|
static void
|
|
|
|
clear_writable(void)
|
|
|
|
{
|
|
|
|
static int zero = 0;
|
|
|
|
dk_ioctl(set_writable_fd, DIOCWLABEL, &zero);
|
|
|
|
}
|
|
|
|
|
1994-09-30 05:33:15 +03:00
|
|
|
int
|
2000-12-24 08:59:11 +03:00
|
|
|
main(int argc, char *argv[])
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-12-24 08:59:11 +03:00
|
|
|
FILE *t;
|
2005-10-20 01:22:21 +04:00
|
|
|
int ch, f, error;
|
|
|
|
char *dkname;
|
|
|
|
struct stat sb;
|
|
|
|
int writable;
|
|
|
|
enum {
|
|
|
|
UNSPEC, EDIT, READ, RESTORE, SETWRITABLE, SETREADONLY,
|
|
|
|
WRITE, INTERACT, DELETE
|
|
|
|
} op = UNSPEC, old_op;
|
|
|
|
|
|
|
|
#ifdef USE_MBR
|
|
|
|
mflag = 1;
|
|
|
|
#endif
|
|
|
|
#if HAVE_NBTOOL_CONFIG_H
|
|
|
|
/* We must avoid doing any ioctl requests */
|
|
|
|
Fflag = rflag = 1;
|
|
|
|
#endif
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2000-12-24 08:59:11 +03:00
|
|
|
error = 0;
|
2005-10-20 01:22:21 +04:00
|
|
|
while ((ch = getopt(argc, argv, "ABCDFINRWb:ef:imrs:tvw")) != -1) {
|
|
|
|
old_op = op;
|
1993-03-21 12:45:37 +03:00
|
|
|
switch (ch) {
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'A': /* Action all labels */
|
|
|
|
Aflag = 1;
|
|
|
|
rflag = 1;
|
1996-06-29 19:50:16 +04:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'C': /* Display in CHS format */
|
|
|
|
Cflag = 1;
|
2004-03-19 21:22:31 +03:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'D': /* Delete all existing labels */
|
|
|
|
Dflag = 1;
|
|
|
|
rflag = 1;
|
2000-05-31 18:13:48 +04:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'F': /* Treat 'disk' as a regular file */
|
|
|
|
Fflag = 1;
|
|
|
|
rflag = 1; /* Force direct access */
|
|
|
|
break;
|
|
|
|
case 'I': /* Use default label if none found */
|
|
|
|
Iflag = 1;
|
|
|
|
rflag = 1; /* Implies direct access */
|
|
|
|
break;
|
|
|
|
case 'R': /* Restore label from text file */
|
2005-06-12 23:18:34 +04:00
|
|
|
op = RESTORE;
|
1994-09-30 05:33:15 +03:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'N': /* Disallow writes to label sector */
|
|
|
|
op = SETREADONLY;
|
1994-09-30 05:33:15 +03:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'W': /* Allow writes to label sector */
|
2003-11-10 12:22:09 +03:00
|
|
|
op = SETWRITABLE;
|
1994-09-30 05:33:15 +03:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'e': /* Edit label with $EDITOR */
|
2003-11-10 12:22:09 +03:00
|
|
|
op = EDIT;
|
1994-09-30 05:33:15 +03:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'f': /* Name of disktab file */
|
1999-01-19 09:24:08 +03:00
|
|
|
if (setdisktab(optarg) == -1)
|
|
|
|
usage();
|
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'i': /* Edit using built-in editor */
|
2003-11-10 12:22:09 +03:00
|
|
|
op = INTERACT;
|
1997-03-09 02:46:08 +03:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'm': /* Expect disk to have an MBR */
|
|
|
|
mflag ^= 1;
|
1996-10-02 17:49:44 +04:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'r': /* Read/write label directly from disk */
|
|
|
|
rflag = 1;
|
1994-09-30 05:33:15 +03:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 't': /* Format output as a disktab entry */
|
|
|
|
tflag = 1;
|
1994-09-30 05:33:15 +03:00
|
|
|
break;
|
2005-10-20 01:22:21 +04:00
|
|
|
case 'v': /* verbose/diag output */
|
|
|
|
verbose++;
|
|
|
|
break;
|
|
|
|
case 'w': /* Write label based on disktab entry */
|
|
|
|
op = WRITE;
|
1994-09-30 05:33:15 +03:00
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
default:
|
|
|
|
usage();
|
2005-10-20 01:22:21 +04:00
|
|
|
}
|
|
|
|
if (old_op != UNSPEC && old_op != op)
|
|
|
|
usage();
|
1994-09-30 05:33:15 +03:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
1994-09-30 05:33:15 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
if (op == UNSPEC)
|
2005-10-20 01:22:21 +04:00
|
|
|
op = Dflag ? DELETE : READ;
|
1994-09-30 05:33:15 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
if (argc < 1)
|
|
|
|
usage();
|
|
|
|
|
2000-10-09 03:32:50 +04:00
|
|
|
if (Iflag && op != EDIT && op != INTERACT)
|
2000-05-31 18:13:48 +04:00
|
|
|
usage();
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
dkname = argv[0];
|
2005-10-20 01:22:21 +04:00
|
|
|
f = opendisk(dkname, op == READ ? O_RDONLY : O_RDWR,
|
|
|
|
specname, sizeof specname, 0);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (f < 0)
|
1994-09-23 02:03:52 +04:00
|
|
|
err(4, "%s", specname);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
if (!Fflag && fstat(f, &sb) == 0 && S_ISREG(sb.st_mode))
|
|
|
|
Fflag = rflag = 1;
|
2000-12-24 08:59:11 +03:00
|
|
|
|
1994-09-30 05:33:15 +03:00
|
|
|
switch (op) {
|
1994-06-24 17:48:17 +04:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
case DELETE: /* Remove all existing labels */
|
|
|
|
if (argc != 1)
|
|
|
|
usage();
|
|
|
|
Dflag = 2;
|
|
|
|
writelabel_direct(f);
|
|
|
|
break;
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
case EDIT:
|
|
|
|
if (argc != 1)
|
|
|
|
usage();
|
2005-10-20 01:22:21 +04:00
|
|
|
readlabel(f);
|
|
|
|
error = edit(f);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
1994-06-24 17:48:17 +04:00
|
|
|
|
1997-03-09 02:46:08 +03:00
|
|
|
case INTERACT:
|
|
|
|
if (argc != 1)
|
|
|
|
usage();
|
2005-10-20 01:22:21 +04:00
|
|
|
readlabel(f);
|
1997-03-09 02:46:08 +03:00
|
|
|
/*
|
|
|
|
* XXX: Fill some default values so checklabel does not fail
|
|
|
|
*/
|
2005-10-20 01:22:21 +04:00
|
|
|
if (lab.d_bbsize == 0)
|
|
|
|
lab.d_bbsize = BBSIZE;
|
|
|
|
if (lab.d_sbsize == 0)
|
|
|
|
lab.d_sbsize = SBLOCKSIZE;
|
|
|
|
interact(&lab, f);
|
1997-03-09 02:46:08 +03:00
|
|
|
break;
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
case READ:
|
|
|
|
if (argc != 1)
|
|
|
|
usage();
|
2005-10-20 01:22:21 +04:00
|
|
|
read_all = Aflag;
|
|
|
|
readlabel(f);
|
|
|
|
if (read_all)
|
|
|
|
/* Label got printed in the bowels of readlabel */
|
|
|
|
break;
|
1996-10-02 17:49:44 +04:00
|
|
|
if (tflag)
|
2005-10-20 01:22:21 +04:00
|
|
|
makedisktab(stdout, &lab);
|
1999-05-03 13:45:01 +04:00
|
|
|
else {
|
2005-10-20 01:22:21 +04:00
|
|
|
showinfo(stdout, &lab, specname);
|
|
|
|
showpartitions(stdout, &lab, Cflag);
|
1999-05-03 13:45:01 +04:00
|
|
|
}
|
2005-10-20 01:22:21 +04:00
|
|
|
error = checklabel(&lab);
|
2004-05-28 21:46:49 +04:00
|
|
|
if (error)
|
|
|
|
error += 100;
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
1994-06-24 17:48:17 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
case RESTORE:
|
2005-10-20 01:22:21 +04:00
|
|
|
if (argc != 2)
|
1994-09-30 05:33:15 +03:00
|
|
|
usage();
|
1994-06-24 17:48:17 +04:00
|
|
|
if (!(t = fopen(argv[1], "r")))
|
1994-09-23 02:03:52 +04:00
|
|
|
err(4, "%s", argv[1]);
|
2005-10-20 01:22:21 +04:00
|
|
|
if (getasciilabel(t, &lab))
|
|
|
|
error = write_label(f);
|
2004-05-28 21:46:49 +04:00
|
|
|
else
|
|
|
|
error = 1;
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
1994-06-24 17:48:17 +04:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
case SETREADONLY:
|
|
|
|
writable = 0;
|
|
|
|
goto do_diocwlabel;
|
2003-01-06 23:30:28 +03:00
|
|
|
case SETWRITABLE:
|
2005-10-20 01:22:21 +04:00
|
|
|
writable = 1;
|
|
|
|
do_diocwlabel:
|
|
|
|
if (argc != 1)
|
|
|
|
usage();
|
|
|
|
if (dk_ioctl(f, DIOCWLABEL, &writable) < 0)
|
1994-09-30 05:33:15 +03:00
|
|
|
err(4, "ioctl DIOCWLABEL");
|
|
|
|
break;
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
case WRITE: /* Create label from /etc/disktab entry & write */
|
1994-09-30 05:33:15 +03:00
|
|
|
if (argc < 2 || argc > 3)
|
1993-03-21 12:45:37 +03:00
|
|
|
usage();
|
2005-10-20 01:22:21 +04:00
|
|
|
makelabel(argv[1], argv[2]);
|
|
|
|
if (checklabel(&lab) == 0)
|
|
|
|
error = write_label(f);
|
1999-04-09 14:06:18 +04:00
|
|
|
else
|
|
|
|
error = 1;
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
1994-06-24 17:48:17 +04:00
|
|
|
|
1996-10-02 17:49:44 +04:00
|
|
|
case UNSPEC:
|
|
|
|
usage();
|
2000-12-24 08:59:11 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1999-04-09 14:06:18 +04:00
|
|
|
exit(error);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-20 01:22:21 +04:00
|
|
|
* Construct a prototype disklabel from /etc/disktab.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
1996-10-02 17:49:44 +04:00
|
|
|
static void
|
2005-10-20 01:22:21 +04:00
|
|
|
makelabel(const char *type, const char *name)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1994-09-30 05:33:15 +03:00
|
|
|
struct disklabel *dp;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
dp = getdiskbyname(type);
|
1994-09-23 02:03:52 +04:00
|
|
|
if (dp == NULL)
|
|
|
|
errx(1, "unknown disk type: %s", type);
|
2005-10-20 01:22:21 +04:00
|
|
|
lab = *dp;
|
2000-12-24 08:59:11 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/* d_packname is union d_boot[01], so zero */
|
2005-10-20 01:22:21 +04:00
|
|
|
(void)memset(lab.d_packname, 0, sizeof(lab.d_packname));
|
1993-03-21 12:45:37 +03:00
|
|
|
if (name)
|
2005-10-20 01:22:21 +04:00
|
|
|
(void)strncpy(lab.d_packname, name, sizeof(lab.d_packname));
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
static int
|
|
|
|
write_label(int f)
|
1998-03-02 19:26:47 +03:00
|
|
|
{
|
2005-10-20 01:22:21 +04:00
|
|
|
int writable;
|
1998-03-02 19:26:47 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
lab.d_magic = DISKMAGIC;
|
|
|
|
lab.d_magic2 = DISKMAGIC;
|
|
|
|
lab.d_checksum = 0;
|
|
|
|
lab.d_checksum = dkcksum(&lab);
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
if (rflag) {
|
|
|
|
/* Write the label directly to the disk */
|
2000-12-24 08:59:11 +03:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* First set the kernel disk label,
|
|
|
|
* then write a label to the raw disk.
|
|
|
|
* If the SDINFO ioctl fails because it is unimplemented,
|
|
|
|
* keep going; otherwise, the kernel consistency checks
|
|
|
|
* may prevent us from changing the current (in-core)
|
|
|
|
* label.
|
|
|
|
*/
|
2005-10-20 01:22:21 +04:00
|
|
|
if (!Fflag && dk_ioctl(f, DIOCSDINFO, &lab) < 0 &&
|
1993-03-21 12:45:37 +03:00
|
|
|
errno != ENODEV && errno != ENOTTY) {
|
|
|
|
l_perror("ioctl DIOCSDINFO");
|
1994-06-24 17:48:17 +04:00
|
|
|
return (1);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
/*
|
|
|
|
* write enable label sector before write (if necessary),
|
|
|
|
* disable after writing.
|
|
|
|
*/
|
2003-01-06 23:30:28 +03:00
|
|
|
writable = 1;
|
2005-10-20 01:22:21 +04:00
|
|
|
if (!Fflag) {
|
|
|
|
if (dk_ioctl(f, DIOCWLABEL, &writable) < 0)
|
|
|
|
perror("ioctl DIOCWLABEL");
|
|
|
|
set_writable_fd = f;
|
|
|
|
atexit(clear_writable);
|
1995-03-23 02:48:49 +03:00
|
|
|
}
|
1997-10-20 00:45:42 +04:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
writelabel_direct(f);
|
2000-12-24 08:59:11 +03:00
|
|
|
|
2003-11-15 20:52:30 +03:00
|
|
|
/*
|
|
|
|
* Now issue a DIOCWDINFO. This will let the kernel convert the
|
|
|
|
* disklabel to some machdep format if needed.
|
|
|
|
*/
|
2005-10-20 01:22:21 +04:00
|
|
|
/* XXX: This is stupid! */
|
|
|
|
if (!Fflag && dk_ioctl(f, DIOCWDINFO, &lab) < 0) {
|
2003-11-15 20:52:30 +03:00
|
|
|
l_perror("ioctl DIOCWDINFO");
|
|
|
|
return (1);
|
|
|
|
}
|
1995-03-22 12:14:34 +03:00
|
|
|
} else {
|
2005-10-20 01:22:21 +04:00
|
|
|
/* Get the kernel to write the label */
|
|
|
|
if (dk_ioctl(f, DIOCWDINFO, &lab) < 0) {
|
1995-03-22 12:14:34 +03:00
|
|
|
l_perror("ioctl DIOCWDINFO");
|
|
|
|
return (1);
|
|
|
|
}
|
1995-03-20 02:37:56 +03:00
|
|
|
}
|
2000-12-24 08:59:11 +03:00
|
|
|
|
1996-10-02 17:49:44 +04:00
|
|
|
#ifdef __vax__
|
2005-10-20 01:22:21 +04:00
|
|
|
if (lab.d_type == DTYPE_SMD && lab.d_flags & D_BADSECT &&
|
|
|
|
lab.d_secsize == 512) {
|
|
|
|
/* Write the label to the odd sectors of the last track! */
|
2000-12-24 08:59:11 +03:00
|
|
|
daddr_t alt;
|
|
|
|
int i;
|
2005-10-20 01:22:21 +04:00
|
|
|
uint8_t sec0[512];
|
|
|
|
|
|
|
|
if (pread(f, sec0, 512, 0) < 512) {
|
|
|
|
warn("read master label to write alternates");
|
|
|
|
return 0;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
alt = lab.d_ncylinders * lab.d_secpercyl - lab.d_nsectors;
|
|
|
|
for (i = 1; i < 11 && i < lab.d_nsectors; i += 2) {
|
|
|
|
if (pwrite(f, sec0, 512, (off_t)(alt + i) * 512) < 512)
|
1994-09-23 02:03:52 +04:00
|
|
|
warn("alternate label %d write", i/2);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
}
|
2000-12-24 08:59:11 +03:00
|
|
|
#endif /* __vax__ */
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
writelabel(int f, struct disklabel *lp)
|
|
|
|
{
|
|
|
|
if (lp != &lab)
|
|
|
|
lab = *lp;
|
|
|
|
return write_label(f);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
1996-10-02 17:49:44 +04:00
|
|
|
static void
|
2000-12-24 08:59:11 +03:00
|
|
|
l_perror(const char *s)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
|
1994-09-23 02:03:52 +04:00
|
|
|
switch (errno) {
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
case ESRCH:
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("%s: No disk label on disk;\n"
|
2000-05-31 18:13:48 +04:00
|
|
|
"use \"disklabel -I\" to install initial label", s);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EINVAL:
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("%s: Label magic number or checksum is wrong!\n"
|
|
|
|
"(disklabel or kernel is out of date?)", s);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EBUSY:
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("%s: Open partition would move or shrink", s);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
case EXDEV:
|
1998-08-04 15:52:52 +04:00
|
|
|
warnx("%s: Labeled partition or 'a' partition must start"
|
|
|
|
" at beginning of disk", s);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
1994-09-23 02:03:52 +04:00
|
|
|
warn("%s", s);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
#ifdef NO_MBR_SUPPORT
|
|
|
|
#define process_mbr(f, action) 1
|
|
|
|
#else
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
2005-10-20 01:22:21 +04:00
|
|
|
* Scan DOS/MBR partition table and extended partition list for NetBSD ptns.
|
1993-03-21 12:45:37 +03:00
|
|
|
*/
|
2005-10-20 01:22:21 +04:00
|
|
|
static int
|
|
|
|
process_mbr(int f, int (*action)(int, u_int))
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-12-24 08:59:11 +03:00
|
|
|
struct mbr_partition *dp;
|
Overhaul MBR handling (part 1):
<sys/bootblock.h>:
* Added definitions for the Master Boot Record (MBR) used by
a variety of systems (primarily i386), including the format
of the BIOS Parameter Block (BPB).
This information was cribbed from a variety of sources
including <sys/disklabel_mbr.h> which this is a superset of.
As part of this, some data structure elements and #defines
were renamed to be more "namespace friendly" and consistent
with other bootblocks and MBR documentation.
Update all uses of the old names to the new names.
<sys/disklabel_mbr.h>:
* Deprecated in favor of <sys/bootblock.h> (the latter is more
"host tool" friendly).
amd64 & i386:
* Renamed /usr/mdec/bootxx_dosfs to /usr/mdec/bootxx_msdos, to
be consistent with the naming convention of the msdosfs tools.
* Removed /usr/mdec/bootxx_ufs, as it's equivalent to bootxx_ffsv1
and it's confusing to have two functionally equivalent bootblocks,
especially given that "ufs" has multiple meanings (it could be
a synonym for "ffs", or the group of ffs/lfs/ext2fs file systems).
* Rework pbr.S (the first sector of bootxx_*):
+ Ensure that BPB (bytes 11..89) and the partition table
(bytes 446..509) do not contain code.
+ Add support for booting from FAT partitions if BOOT_FROM_FAT
is defined. (Only set for bootxx_msdos).
+ Remove "dummy" partition 3; if people want to installboot(8)
these to the start of the disk they can use fdisk(8) to
create a real MBR partition table...
+ Compile with TERSE_ERROR so it fits because of the above.
Whilst this is less user friendly, I feel it's important
to have a valid partition table and BPB in the MBR/PBR.
* Renamed /usr/mdec/biosboot to /usr/mdec/boot, to be consistent
with other platforms.
* Enable SUPPORT_DOSFS in /usr/mdec/boot (stage2), so that
we can boot off FAT partitions.
* Crank version of /usr/mdec/boot to 3.1, and fix some of the other
entries in the version file.
installboot(8) (i386):
* Read the existing MBR of the filesystem and retain the BIOS
Parameter Block (BPB) in bytes 11..89 and the MBR partition
table in bytes 446..509. (Previously installboot(8) would
trash those two sections of the MBR.)
mbrlabel(8):
* Use sys/lib/libkern/xlat_mbr_fstype.c instead of homegrown code
to map the MBR partition type to the NetBSD disklabel type.
Test built "make release" for i386, and new bootblocks verified to work
(even off FAT!).
2003-10-08 08:25:43 +04:00
|
|
|
struct mbr_sector mbr;
|
2005-10-20 01:22:21 +04:00
|
|
|
int rval = 1, res;
|
2003-07-07 17:05:46 +04:00
|
|
|
int part;
|
2005-10-20 01:22:21 +04:00
|
|
|
u_int ext_base, next_ext, this_ext, start;
|
2003-07-07 17:05:46 +04:00
|
|
|
|
|
|
|
ext_base = 0;
|
|
|
|
next_ext = 0;
|
|
|
|
for (;;) {
|
2003-08-04 20:51:56 +04:00
|
|
|
this_ext = next_ext;
|
2004-01-18 19:25:59 +03:00
|
|
|
next_ext = 0;
|
2005-10-20 01:22:21 +04:00
|
|
|
if (verbose > 1)
|
|
|
|
warnx("reading mbr sector %u", this_ext);
|
2004-01-18 19:25:59 +03:00
|
|
|
if (pread(f, &mbr, sizeof mbr, this_ext * (off_t)DEV_BSIZE)
|
2003-07-07 17:05:46 +04:00
|
|
|
!= sizeof(mbr)) {
|
2005-10-20 01:22:21 +04:00
|
|
|
if (verbose)
|
|
|
|
warn("Can't read master boot record %d",
|
|
|
|
this_ext);
|
|
|
|
break;
|
2003-07-07 17:05:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Check if table is valid. */
|
Overhaul MBR handling (part 1):
<sys/bootblock.h>:
* Added definitions for the Master Boot Record (MBR) used by
a variety of systems (primarily i386), including the format
of the BIOS Parameter Block (BPB).
This information was cribbed from a variety of sources
including <sys/disklabel_mbr.h> which this is a superset of.
As part of this, some data structure elements and #defines
were renamed to be more "namespace friendly" and consistent
with other bootblocks and MBR documentation.
Update all uses of the old names to the new names.
<sys/disklabel_mbr.h>:
* Deprecated in favor of <sys/bootblock.h> (the latter is more
"host tool" friendly).
amd64 & i386:
* Renamed /usr/mdec/bootxx_dosfs to /usr/mdec/bootxx_msdos, to
be consistent with the naming convention of the msdosfs tools.
* Removed /usr/mdec/bootxx_ufs, as it's equivalent to bootxx_ffsv1
and it's confusing to have two functionally equivalent bootblocks,
especially given that "ufs" has multiple meanings (it could be
a synonym for "ffs", or the group of ffs/lfs/ext2fs file systems).
* Rework pbr.S (the first sector of bootxx_*):
+ Ensure that BPB (bytes 11..89) and the partition table
(bytes 446..509) do not contain code.
+ Add support for booting from FAT partitions if BOOT_FROM_FAT
is defined. (Only set for bootxx_msdos).
+ Remove "dummy" partition 3; if people want to installboot(8)
these to the start of the disk they can use fdisk(8) to
create a real MBR partition table...
+ Compile with TERSE_ERROR so it fits because of the above.
Whilst this is less user friendly, I feel it's important
to have a valid partition table and BPB in the MBR/PBR.
* Renamed /usr/mdec/biosboot to /usr/mdec/boot, to be consistent
with other platforms.
* Enable SUPPORT_DOSFS in /usr/mdec/boot (stage2), so that
we can boot off FAT partitions.
* Crank version of /usr/mdec/boot to 3.1, and fix some of the other
entries in the version file.
installboot(8) (i386):
* Read the existing MBR of the filesystem and retain the BIOS
Parameter Block (BPB) in bytes 11..89 and the MBR partition
table in bytes 446..509. (Previously installboot(8) would
trash those two sections of the MBR.)
mbrlabel(8):
* Use sys/lib/libkern/xlat_mbr_fstype.c instead of homegrown code
to map the MBR partition type to the NetBSD disklabel type.
Test built "make release" for i386, and new bootblocks verified to work
(even off FAT!).
2003-10-08 08:25:43 +04:00
|
|
|
if (mbr.mbr_magic != htole16(MBR_MAGIC)) {
|
2005-10-20 01:22:21 +04:00
|
|
|
if (verbose)
|
|
|
|
warnx("Invalid signature in mbr record %d",
|
|
|
|
this_ext);
|
|
|
|
break;
|
2003-07-07 17:05:46 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
dp = &mbr.mbr_parts[0];
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
/* Find NetBSD partition(s). */
|
Overhaul MBR handling (part 1):
<sys/bootblock.h>:
* Added definitions for the Master Boot Record (MBR) used by
a variety of systems (primarily i386), including the format
of the BIOS Parameter Block (BPB).
This information was cribbed from a variety of sources
including <sys/disklabel_mbr.h> which this is a superset of.
As part of this, some data structure elements and #defines
were renamed to be more "namespace friendly" and consistent
with other bootblocks and MBR documentation.
Update all uses of the old names to the new names.
<sys/disklabel_mbr.h>:
* Deprecated in favor of <sys/bootblock.h> (the latter is more
"host tool" friendly).
amd64 & i386:
* Renamed /usr/mdec/bootxx_dosfs to /usr/mdec/bootxx_msdos, to
be consistent with the naming convention of the msdosfs tools.
* Removed /usr/mdec/bootxx_ufs, as it's equivalent to bootxx_ffsv1
and it's confusing to have two functionally equivalent bootblocks,
especially given that "ufs" has multiple meanings (it could be
a synonym for "ffs", or the group of ffs/lfs/ext2fs file systems).
* Rework pbr.S (the first sector of bootxx_*):
+ Ensure that BPB (bytes 11..89) and the partition table
(bytes 446..509) do not contain code.
+ Add support for booting from FAT partitions if BOOT_FROM_FAT
is defined. (Only set for bootxx_msdos).
+ Remove "dummy" partition 3; if people want to installboot(8)
these to the start of the disk they can use fdisk(8) to
create a real MBR partition table...
+ Compile with TERSE_ERROR so it fits because of the above.
Whilst this is less user friendly, I feel it's important
to have a valid partition table and BPB in the MBR/PBR.
* Renamed /usr/mdec/biosboot to /usr/mdec/boot, to be consistent
with other platforms.
* Enable SUPPORT_DOSFS in /usr/mdec/boot (stage2), so that
we can boot off FAT partitions.
* Crank version of /usr/mdec/boot to 3.1, and fix some of the other
entries in the version file.
installboot(8) (i386):
* Read the existing MBR of the filesystem and retain the BIOS
Parameter Block (BPB) in bytes 11..89 and the MBR partition
table in bytes 446..509. (Previously installboot(8) would
trash those two sections of the MBR.)
mbrlabel(8):
* Use sys/lib/libkern/xlat_mbr_fstype.c instead of homegrown code
to map the MBR partition type to the NetBSD disklabel type.
Test built "make release" for i386, and new bootblocks verified to work
(even off FAT!).
2003-10-08 08:25:43 +04:00
|
|
|
for (part = 0; part < MBR_PART_COUNT; dp++, part++) {
|
2005-10-20 01:22:21 +04:00
|
|
|
start = le32toh(dp->mbrp_start);
|
Overhaul MBR handling (part 1):
<sys/bootblock.h>:
* Added definitions for the Master Boot Record (MBR) used by
a variety of systems (primarily i386), including the format
of the BIOS Parameter Block (BPB).
This information was cribbed from a variety of sources
including <sys/disklabel_mbr.h> which this is a superset of.
As part of this, some data structure elements and #defines
were renamed to be more "namespace friendly" and consistent
with other bootblocks and MBR documentation.
Update all uses of the old names to the new names.
<sys/disklabel_mbr.h>:
* Deprecated in favor of <sys/bootblock.h> (the latter is more
"host tool" friendly).
amd64 & i386:
* Renamed /usr/mdec/bootxx_dosfs to /usr/mdec/bootxx_msdos, to
be consistent with the naming convention of the msdosfs tools.
* Removed /usr/mdec/bootxx_ufs, as it's equivalent to bootxx_ffsv1
and it's confusing to have two functionally equivalent bootblocks,
especially given that "ufs" has multiple meanings (it could be
a synonym for "ffs", or the group of ffs/lfs/ext2fs file systems).
* Rework pbr.S (the first sector of bootxx_*):
+ Ensure that BPB (bytes 11..89) and the partition table
(bytes 446..509) do not contain code.
+ Add support for booting from FAT partitions if BOOT_FROM_FAT
is defined. (Only set for bootxx_msdos).
+ Remove "dummy" partition 3; if people want to installboot(8)
these to the start of the disk they can use fdisk(8) to
create a real MBR partition table...
+ Compile with TERSE_ERROR so it fits because of the above.
Whilst this is less user friendly, I feel it's important
to have a valid partition table and BPB in the MBR/PBR.
* Renamed /usr/mdec/biosboot to /usr/mdec/boot, to be consistent
with other platforms.
* Enable SUPPORT_DOSFS in /usr/mdec/boot (stage2), so that
we can boot off FAT partitions.
* Crank version of /usr/mdec/boot to 3.1, and fix some of the other
entries in the version file.
installboot(8) (i386):
* Read the existing MBR of the filesystem and retain the BIOS
Parameter Block (BPB) in bytes 11..89 and the MBR partition
table in bytes 446..509. (Previously installboot(8) would
trash those two sections of the MBR.)
mbrlabel(8):
* Use sys/lib/libkern/xlat_mbr_fstype.c instead of homegrown code
to map the MBR partition type to the NetBSD disklabel type.
Test built "make release" for i386, and new bootblocks verified to work
(even off FAT!).
2003-10-08 08:25:43 +04:00
|
|
|
switch (dp->mbrp_type) {
|
2005-10-20 01:22:21 +04:00
|
|
|
#ifdef COMPAT_386BSD_MBRPART
|
|
|
|
case MBR_PTYPE_386BSD:
|
|
|
|
if (ext_base != 0)
|
|
|
|
break;
|
|
|
|
/* FALLTHROUGH */
|
|
|
|
#endif
|
2003-07-07 17:05:46 +04:00
|
|
|
case MBR_PTYPE_NETBSD:
|
2005-10-20 01:22:21 +04:00
|
|
|
res = action(f, this_ext + start);
|
|
|
|
if (res <= 0)
|
|
|
|
/* Found or failure */
|
|
|
|
return res;
|
|
|
|
if (res > rval)
|
|
|
|
/* Keep largest value */
|
|
|
|
rval = res;
|
2003-07-07 17:05:46 +04:00
|
|
|
break;
|
|
|
|
case MBR_PTYPE_EXT:
|
|
|
|
case MBR_PTYPE_EXT_LBA:
|
|
|
|
case MBR_PTYPE_EXT_LNX:
|
2005-10-20 01:22:21 +04:00
|
|
|
next_ext = start;
|
|
|
|
break;
|
2003-07-07 17:05:46 +04:00
|
|
|
default:
|
2005-10-20 01:22:21 +04:00
|
|
|
break;
|
2003-07-07 17:05:46 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (next_ext == 0)
|
|
|
|
/* No more extended partitions */
|
|
|
|
break;
|
2004-01-18 19:25:59 +03:00
|
|
|
next_ext += ext_base;
|
|
|
|
if (ext_base == 0)
|
|
|
|
ext_base = next_ext;
|
|
|
|
|
2003-08-04 20:51:56 +04:00
|
|
|
if (next_ext <= this_ext) {
|
2005-10-20 01:22:21 +04:00
|
|
|
if (verbose)
|
|
|
|
warnx("Invalid extended chain %x <= %x",
|
|
|
|
next_ext, this_ext);
|
2003-08-04 20:51:56 +04:00
|
|
|
break;
|
|
|
|
}
|
2005-10-20 01:22:21 +04:00
|
|
|
/* Maybe we should check against the disk size... */
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1998-03-02 19:26:47 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
return rval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
readlabel_mbr(int f, u_int sector)
|
|
|
|
{
|
|
|
|
struct disklabel *lp;
|
2003-07-07 17:05:46 +04:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
lp = find_label(f, sector);
|
|
|
|
if (lp == NULL)
|
|
|
|
return 1;
|
|
|
|
lab = *lp;
|
|
|
|
return 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
static int
|
|
|
|
writelabel_mbr(int f, u_int sector)
|
|
|
|
{
|
|
|
|
return update_label(f, sector, mflag ? LABELOFFSET_MBR : ~0U) ? 2 : 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* !NO_MBR_SUPPORT */
|
|
|
|
|
|
|
|
#ifndef USE_ACORN
|
|
|
|
#define get_filecore_partition(f) 0
|
|
|
|
#else
|
1997-10-18 01:29:36 +04:00
|
|
|
/*
|
1998-06-08 00:33:22 +04:00
|
|
|
* static int filecore_checksum(u_char *bootblock)
|
1997-10-18 01:29:36 +04:00
|
|
|
*
|
|
|
|
* Calculates the filecore boot block checksum. This is used to validate
|
1998-06-08 00:33:22 +04:00
|
|
|
* a filecore boot block on the disk. If a boot block is validated then
|
1997-10-18 01:29:36 +04:00
|
|
|
* it is used to locate the partition table. If the boot block is not
|
1998-06-08 00:33:22 +04:00
|
|
|
* validated, it is assumed that the whole disk is NetBSD.
|
|
|
|
*
|
|
|
|
* The basic algorithm is:
|
|
|
|
*
|
|
|
|
* for (each byte in block, excluding checksum) {
|
|
|
|
* sum += byte;
|
|
|
|
* if (sum > 255)
|
|
|
|
* sum -= 255;
|
|
|
|
* }
|
|
|
|
*
|
|
|
|
* That's equivalent to summing all of the bytes in the block
|
|
|
|
* (excluding the checksum byte, of course), then calculating the
|
|
|
|
* checksum as "cksum = sum - ((sum - 1) / 255) * 255)". That
|
|
|
|
* expression may or may not yield a faster checksum function,
|
|
|
|
* but it's easier to reason about.
|
|
|
|
*
|
|
|
|
* Note that if you have a block filled with bytes of a single
|
|
|
|
* value "X" (regardless of that value!) and calculate the cksum
|
|
|
|
* of the block (excluding the checksum byte), you will _always_
|
|
|
|
* end up with a checksum of X. (Do the math; that can be derived
|
|
|
|
* from the checksum calculation function!) That means that
|
|
|
|
* blocks which contain bytes which all have the same value will
|
|
|
|
* always checksum properly. That's a _very_ unlikely occurence
|
|
|
|
* (probably impossible, actually) for a valid filecore boot block,
|
|
|
|
* so we treat such blocks as invalid.
|
1997-10-18 01:29:36 +04:00
|
|
|
*/
|
1998-06-08 00:33:22 +04:00
|
|
|
static int
|
2000-12-24 08:59:11 +03:00
|
|
|
filecore_checksum(u_char *bootblock)
|
1997-10-18 01:29:36 +04:00
|
|
|
{
|
2000-12-24 08:59:11 +03:00
|
|
|
u_char byte0, accum_diff;
|
|
|
|
u_int sum;
|
|
|
|
int i;
|
2001-01-03 09:55:30 +03:00
|
|
|
|
1997-10-18 01:29:36 +04:00
|
|
|
sum = 0;
|
1998-06-08 00:33:22 +04:00
|
|
|
accum_diff = 0;
|
|
|
|
byte0 = bootblock[0];
|
1997-10-18 01:29:36 +04:00
|
|
|
|
1998-06-08 00:33:22 +04:00
|
|
|
/*
|
|
|
|
* Sum the contents of the block, keeping track of whether
|
|
|
|
* or not all bytes are the same. If 'accum_diff' ends up
|
|
|
|
* being zero, all of the bytes are, in fact, the same.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < 511; ++i) {
|
|
|
|
sum += bootblock[i];
|
|
|
|
accum_diff |= bootblock[i] ^ byte0;
|
|
|
|
}
|
1997-10-18 01:29:36 +04:00
|
|
|
|
1998-06-08 00:33:22 +04:00
|
|
|
/*
|
|
|
|
* Check to see if the checksum byte is the same as the
|
|
|
|
* rest of the bytes, too. (Note that if all of the bytes
|
|
|
|
* are the same except the checksum, a checksum compare
|
|
|
|
* won't succeed, but that's not our problem.)
|
|
|
|
*/
|
|
|
|
accum_diff |= bootblock[i] ^ byte0;
|
1997-10-18 01:29:36 +04:00
|
|
|
|
1998-06-08 00:33:22 +04:00
|
|
|
/* All bytes in block are the same; call it invalid. */
|
|
|
|
if (accum_diff == 0)
|
|
|
|
return (-1);
|
1997-10-18 01:29:36 +04:00
|
|
|
|
1998-06-08 00:33:22 +04:00
|
|
|
return (sum - ((sum - 1) / 255) * 255);
|
1997-10-18 01:29:36 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-20 01:22:21 +04:00
|
|
|
* Check for the presence of a RiscOS filecore boot block
|
|
|
|
* indicating an ADFS file system on the disc.
|
|
|
|
* Return the offset to the NetBSD part of the disc if
|
|
|
|
* this can be determined.
|
|
|
|
* This routine will terminate disklabel if the disc
|
|
|
|
* is found to be ADFS only.
|
1997-10-18 01:29:36 +04:00
|
|
|
*/
|
|
|
|
static u_int
|
2000-12-24 08:59:11 +03:00
|
|
|
get_filecore_partition(int f)
|
1997-10-18 01:29:36 +04:00
|
|
|
{
|
2000-12-24 08:59:11 +03:00
|
|
|
struct filecore_bootblock *fcbb;
|
|
|
|
static char bb[DEV_BSIZE];
|
|
|
|
u_int offset;
|
2005-10-20 01:22:21 +04:00
|
|
|
struct riscix_partition_table *riscix_part;
|
|
|
|
int loop;
|
1997-10-18 01:29:36 +04:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
if (pread(f, bb, sizeof(bb), (off_t)FILECORE_BOOT_SECTOR * DEV_BSIZE) != sizeof(bb))
|
1997-10-18 01:29:36 +04:00
|
|
|
err(4, "can't read filecore boot block");
|
1998-03-25 02:45:31 +03:00
|
|
|
fcbb = (struct filecore_bootblock *)bb;
|
1997-10-18 01:29:36 +04:00
|
|
|
|
|
|
|
/* Check if table is valid. */
|
|
|
|
if (filecore_checksum(bb) != fcbb->checksum)
|
1998-03-25 02:45:31 +03:00
|
|
|
return (0);
|
1997-10-18 01:29:36 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for NetBSD/arm32 (RiscBSD) partition marker.
|
|
|
|
* If found the NetBSD disklabel location is easy.
|
|
|
|
*/
|
|
|
|
offset = (fcbb->partition_cyl_low + (fcbb->partition_cyl_high << 8))
|
|
|
|
* fcbb->heads * fcbb->secspertrack;
|
2005-10-20 01:22:21 +04:00
|
|
|
|
|
|
|
switch (fcbb->partition_type) {
|
|
|
|
|
|
|
|
case PARTITION_FORMAT_RISCBSD:
|
1998-03-25 02:45:31 +03:00
|
|
|
return (offset);
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
case PARTITION_FORMAT_RISCIX:
|
1997-10-18 01:29:36 +04:00
|
|
|
/*
|
1998-03-25 02:45:31 +03:00
|
|
|
* Read the RISCiX partition table and search for the
|
|
|
|
* first partition named "RiscBSD", "NetBSD", or "Empty:"
|
|
|
|
*
|
|
|
|
* XXX is use of 'Empty:' really desirable?! -- cgd
|
1997-10-18 01:29:36 +04:00
|
|
|
*/
|
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
if (pread(f, bb, sizeof(bb), (off_t)offset * DEV_BSIZE) != sizeof(bb))
|
1997-10-18 01:29:36 +04:00
|
|
|
err(4, "can't read riscix partition table");
|
1998-03-25 02:45:31 +03:00
|
|
|
riscix_part = (struct riscix_partition_table *)bb;
|
1997-10-18 01:29:36 +04:00
|
|
|
|
|
|
|
for (loop = 0; loop < NRISCIX_PARTITIONS; ++loop) {
|
1998-03-25 02:45:31 +03:00
|
|
|
if (strcmp(riscix_part->partitions[loop].rp_name,
|
2005-10-20 01:22:21 +04:00
|
|
|
"RiscBSD") == 0 ||
|
1998-03-25 02:45:31 +03:00
|
|
|
strcmp(riscix_part->partitions[loop].rp_name,
|
2005-10-20 01:22:21 +04:00
|
|
|
"NetBSD") == 0 ||
|
1998-03-25 02:45:31 +03:00
|
|
|
strcmp(riscix_part->partitions[loop].rp_name,
|
2005-10-20 01:22:21 +04:00
|
|
|
"Empty:") == 0) {
|
|
|
|
return riscix_part->partitions[loop].rp_start;
|
1997-10-18 01:29:36 +04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2005-10-20 01:22:21 +04:00
|
|
|
/*
|
|
|
|
* Valid filecore boot block, RISCiX partition table
|
|
|
|
* but no NetBSD partition. We should leave this
|
|
|
|
* disc alone.
|
|
|
|
*/
|
|
|
|
errx(4, "cannot label: no NetBSD partition found"
|
|
|
|
" in RISCiX partition table");
|
|
|
|
|
|
|
|
default:
|
1997-10-18 01:29:36 +04:00
|
|
|
/*
|
|
|
|
* Valid filecore boot block and no non-ADFS partition.
|
2001-01-03 09:55:30 +03:00
|
|
|
* This means that the whole disc is allocated for ADFS
|
1997-10-18 01:29:36 +04:00
|
|
|
* so do not trash ! If the user really wants to put a
|
|
|
|
* NetBSD disklabel on the disc then they should remove
|
|
|
|
* the filecore boot block first with dd.
|
|
|
|
*/
|
1998-08-04 15:52:52 +04:00
|
|
|
errx(4, "cannot label: filecore-only disk"
|
|
|
|
" (no non-ADFS partition)");
|
1997-10-18 01:29:36 +04:00
|
|
|
}
|
1998-03-25 02:45:31 +03:00
|
|
|
return (0);
|
1997-10-18 01:29:36 +04:00
|
|
|
}
|
2001-11-30 02:08:53 +03:00
|
|
|
#endif /* USE_ACORN */
|
1997-10-18 01:29:36 +04:00
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
2005-10-20 01:22:21 +04:00
|
|
|
* Fetch disklabel for disk to 'lab'.
|
1993-03-21 12:45:37 +03:00
|
|
|
* Use ioctl to get label unless -r flag is given.
|
|
|
|
*/
|
2005-10-20 01:22:21 +04:00
|
|
|
static void
|
2000-12-24 08:59:11 +03:00
|
|
|
readlabel(int f)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2005-10-20 01:22:21 +04:00
|
|
|
if (rflag) {
|
|
|
|
/* Get label directly from disk */
|
|
|
|
if (readlabel_direct(f) == 0)
|
|
|
|
return;
|
2000-05-31 18:13:48 +04:00
|
|
|
/*
|
|
|
|
* There was no label on the disk. Get the fictious one
|
|
|
|
* as a basis for initialisation.
|
|
|
|
*/
|
2005-10-20 01:22:21 +04:00
|
|
|
if (!Fflag && Iflag && (dk_ioctl(f, DIOCGDINFO, &lab) == 0 ||
|
|
|
|
dk_ioctl(f, DIOCGDEFLABEL, &lab) == 0))
|
|
|
|
return;
|
1993-03-21 12:45:37 +03:00
|
|
|
} else {
|
2005-10-20 01:22:21 +04:00
|
|
|
/* Get label from kernel. */
|
|
|
|
if (dk_ioctl(f, DIOCGDINFO, &lab) < 0)
|
1994-09-23 02:03:52 +04:00
|
|
|
err(4, "ioctl DIOCGDINFO");
|
2005-10-20 01:22:21 +04:00
|
|
|
return;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2005-10-20 01:22:21 +04:00
|
|
|
|
|
|
|
if (read_all == 2)
|
|
|
|
/* We actually found one, and printed it... */
|
|
|
|
exit(0);
|
|
|
|
errx(1, "could not read existing label");
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
1994-06-24 17:48:17 +04:00
|
|
|
/*
|
2005-10-20 01:22:21 +04:00
|
|
|
* Reading the label from the disk is largely a case of 'hunt the label'.
|
|
|
|
* and since different architectures default to different places there
|
|
|
|
* could even be more than one label that contradict each other!
|
|
|
|
* For now we look in the expected place, then search through likely
|
|
|
|
* other locations.
|
1994-06-24 17:48:17 +04:00
|
|
|
*/
|
1996-10-02 17:49:44 +04:00
|
|
|
static struct disklabel *
|
2005-10-20 01:22:21 +04:00
|
|
|
find_label(int f, u_int sector)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
struct disklabel *lp;
|
2005-10-20 01:22:21 +04:00
|
|
|
int i, offset;
|
|
|
|
const char *is_deleted;
|
|
|
|
|
|
|
|
bootarea_len = pread(f, bootarea, sizeof bootarea,
|
|
|
|
sector * (off_t)DEV_BSIZE);
|
|
|
|
if (bootarea_len <= 0) {
|
|
|
|
if (verbose)
|
|
|
|
warn("failed to read bootarea from sector %u", sector);
|
|
|
|
return NULL;
|
1994-06-24 17:48:17 +04:00
|
|
|
}
|
2000-12-24 08:59:11 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
if (verbose > 2)
|
|
|
|
warnx("read sector %u len %u looking for label",
|
|
|
|
sector, bootarea_len);
|
|
|
|
|
|
|
|
/* Check expected offset first */
|
|
|
|
for (offset = LABEL_OFFSET, i = -4;; offset = i += 4) {
|
|
|
|
is_deleted = "";
|
|
|
|
lp = (void *)((char *)bootarea + offset);
|
|
|
|
if (i == LABEL_OFFSET)
|
|
|
|
continue;
|
|
|
|
if ((char *)(lp + 1) > (char *)bootarea + bootarea_len)
|
|
|
|
break;
|
|
|
|
if (lp->d_magic2 != lp->d_magic)
|
|
|
|
continue;
|
|
|
|
if (read_all && (lp->d_magic == DISKMAGIC_DELETED ||
|
|
|
|
lp->d_magic == DISKMAGIC_DELETED_REV)) {
|
|
|
|
lp->d_magic ^= ~0u;
|
|
|
|
lp->d_magic2 ^= ~0u;
|
|
|
|
is_deleted = "deleted ";
|
|
|
|
}
|
|
|
|
if (lp->d_magic != DISKMAGIC) {
|
|
|
|
/* XXX: Do something about byte-swapped labels ? */
|
|
|
|
if (lp->d_magic == DISKMAGIC_REV &&
|
|
|
|
lp->d_magic2 == DISKMAGIC_REV)
|
|
|
|
warnx("ignoring %sbyteswapped label"
|
|
|
|
" at offset %u from sector %u",
|
|
|
|
is_deleted, offset, sector);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (lp->d_npartitions > MAXPARTITIONS || dkcksum(lp) != 0) {
|
|
|
|
if (verbose > 0)
|
|
|
|
warnx("corrupt label found at offset %u in "
|
|
|
|
"sector %u", offset, sector);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (verbose > 1)
|
|
|
|
warnx("%slabel found at offset %u from sector %u",
|
|
|
|
is_deleted, offset, sector);
|
|
|
|
if (!read_all)
|
|
|
|
return lp;
|
|
|
|
|
|
|
|
/* To print all the labels we have to do it here */
|
|
|
|
/* XXX: maybe we should compare them? */
|
|
|
|
printf("# %ssector %u offset %u bytes\n",
|
|
|
|
is_deleted, sector, offset);
|
|
|
|
if (tflag)
|
|
|
|
makedisktab(stdout, lp);
|
|
|
|
else {
|
|
|
|
showinfo(stdout, lp, specname);
|
|
|
|
showpartitions(stdout, lp, Cflag);
|
|
|
|
}
|
|
|
|
checklabel(lp);
|
|
|
|
/* Remember we've found a label */
|
|
|
|
read_all = 2;
|
1999-06-03 05:58:51 +04:00
|
|
|
}
|
2005-10-20 01:22:21 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
2000-12-24 08:59:11 +03:00
|
|
|
|
2005-10-20 01:22:21 +04:00
|
|
|
static void
|
|
|
|
write_bootarea(int f, u_int sector)
|
|
|
|
{
|
|
|
|
int wlen;
|
|
|
|
|
|
|
|
if (bootarea_len <= 0)
|
|
|
|
errx(1, "attempting to write after failed read");
|
|
|
|
|
|
|
|
#ifdef __alpha__
|
2003-11-10 12:22:09 +03:00
|
|
|
/*
|
2005-10-20 01:22:21 +04:00
|
|
|
* The Alpha requires that the boot block be checksummed.
|
|
|
|
* The NetBSD/alpha disklabel.h provides a macro to do it.
|
2003-11-10 12:22:09 +03:00
|
|
|
*/
|
2005-10-20 01:22:21 +04:00
|
|
|
if (sector == 0) {
|
|
|
|
struct alpha_boot_block *bb;
|
|
|
|
|
2005-10-21 00:08:33 +04:00
|
|
|
bb = (struct alpha_boot_block *)bootarea;
|
2005-10-20 01:22:21 +04:00
|
|
|
bb->bb_cksum = 0;
|
|
|
|
ALPHA_BOOT_BLOCK_CKSUM(bb, &bb->bb_cksum);
|
|
|
|
}
|
|
|
|
#endif /* __alpha__ */
|
|
|
|
|
|
|
|
wlen = pwrite(f, bootarea, bootarea_len, sector * (off_t)DEV_BSIZE);
|
|
|
|
if (wlen == bootarea_len)
|
|
|
|
return;
|
|
|
|
if (wlen == -1)
|
|
|
|
err(1, "disklabel write (sector %u) size %u failed",
|
|
|
|
sector, bootarea_len);
|
|
|
|
errx(1, "disklabel write (sector %u) size %u truncated to %d",
|
|
|
|
sector, bootarea_len, wlen);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
update_label(int f, u_int label_sector, u_int label_offset)
|
|
|
|
{
|
|
|
|
struct disklabel *disk_lp;
|
|
|
|
|
|
|
|
disk_lp = find_label(f, label_sector);
|
|
|
|
|
|
|
|
if (disk_lp && Dflag) {
|
|
|
|
/* Invalidate the existing label */
|
|
|
|
disk_lp->d_magic ^= ~0u;
|
|
|
|
disk_lp->d_magic2 ^= ~0u;
|
|
|
|
if (Dflag == 2)
|
|
|
|
write_bootarea(f, label_sector);
|
|
|
|
/* Force label to default location */
|
|
|
|
disk_lp = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Dflag == 2)
|
|
|
|
/* We are just deleting the label */
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (disk_lp == NULL) {
|
|
|
|
if (label_offset == ~0u)
|
|
|
|
return 0;
|
|
|
|
/* Nothing on the disk - we need to add it */
|
|
|
|
disk_lp = (void *)((char *)bootarea + label_offset);
|
|
|
|
if ((char *)(disk_lp + 1) > (char *)bootarea + bootarea_len)
|
|
|
|
errx(1, "no space in bootarea (sector %u) "
|
|
|
|
"to create label", label_sector);
|
|
|
|
}
|
|
|
|
|
|
|
|
*disk_lp = lab;
|
|
|
|
write_bootarea(f, label_sector);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
writelabel_direct(int f)
|
|
|
|
{
|
|
|
|
u_int label_sector;
|
|
|
|
int written = 0;
|
|
|
|
int rval;
|
|
|
|
|
|
|
|
label_sector = get_filecore_partition(f);
|
|
|
|
if (label_sector != 0)
|
|
|
|
/* The offset needs to be that from the acorn ports... */
|
|
|
|
written = update_label(f, label_sector, DEV_BSIZE);
|
|
|
|
|
|
|
|
rval = process_mbr(f, writelabel_mbr);
|
|
|
|
|
|
|
|
if (rval == 2 || written)
|
|
|
|
/* Don't add a label to sector 0, but update one if there */
|
|
|
|
update_label(f, 0, ~0u);
|
|
|
|
else
|
|
|
|
update_label(f, 0, LABEL_OFFSET);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
readlabel_direct(int f)
|
|
|
|
{
|
|
|
|
struct disklabel *disk_lp;
|
|
|
|
u_int filecore_partition_offset;
|
|
|
|
|
|
|
|
filecore_partition_offset = get_filecore_partition(f);
|
|
|
|
if (filecore_partition_offset != 0) {
|
|
|
|
disk_lp = find_label(f, filecore_partition_offset);
|
|
|
|
if (disk_lp != NULL) {
|
|
|
|
lab = *disk_lp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mflag && process_mbr(f, readlabel_mbr) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
disk_lp = find_label(f, 0);
|
|
|
|
if (disk_lp != NULL) {
|
|
|
|
lab = *disk_lp;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!mflag && process_mbr(f, readlabel_mbr) == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
return 1;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
1996-10-02 17:49:44 +04:00
|
|
|
static void
|
2000-12-24 08:59:11 +03:00
|
|
|
makedisktab(FILE *f, struct disklabel *lp)
|
1996-10-02 17:49:44 +04:00
|
|
|
{
|
2000-12-24 08:59:11 +03:00
|
|
|
int i;
|
|
|
|
const char *did;
|
1996-10-02 17:49:44 +04:00
|
|
|
struct partition *pp;
|
|
|
|
|
2000-12-24 08:59:11 +03:00
|
|
|
did = "\\\n\t:";
|
1996-10-02 17:49:44 +04:00
|
|
|
(void) fprintf(f, "%.*s|Automatically generated label:\\\n\t:dt=",
|
1997-07-01 02:51:27 +04:00
|
|
|
(int) sizeof(lp->d_typename), lp->d_typename);
|
1996-10-02 17:49:44 +04:00
|
|
|
if ((unsigned) lp->d_type < DKMAXTYPES)
|
|
|
|
(void) fprintf(f, "%s:", dktypenames[lp->d_type]);
|
|
|
|
else
|
|
|
|
(void) fprintf(f, "unknown%d:", lp->d_type);
|
|
|
|
|
|
|
|
(void) fprintf(f, "se#%d:", lp->d_secsize);
|
|
|
|
(void) fprintf(f, "ns#%d:", lp->d_nsectors);
|
|
|
|
(void) fprintf(f, "nt#%d:", lp->d_ntracks);
|
|
|
|
(void) fprintf(f, "sc#%d:", lp->d_secpercyl);
|
|
|
|
(void) fprintf(f, "nc#%d:", lp->d_ncylinders);
|
|
|
|
|
1999-04-29 23:12:07 +04:00
|
|
|
if ((lp->d_secpercyl * lp->d_ncylinders) != lp->d_secperunit) {
|
|
|
|
(void) fprintf(f, "%ssu#%d:", did, lp->d_secperunit);
|
|
|
|
did = "";
|
|
|
|
}
|
1996-10-02 17:49:44 +04:00
|
|
|
if (lp->d_rpm != 3600) {
|
|
|
|
(void) fprintf(f, "%srm#%d:", did, lp->d_rpm);
|
|
|
|
did = "";
|
|
|
|
}
|
|
|
|
if (lp->d_interleave != 1) {
|
|
|
|
(void) fprintf(f, "%sil#%d:", did, lp->d_interleave);
|
|
|
|
did = "";
|
|
|
|
}
|
|
|
|
if (lp->d_trackskew != 0) {
|
|
|
|
(void) fprintf(f, "%ssk#%d:", did, lp->d_trackskew);
|
|
|
|
did = "";
|
|
|
|
}
|
|
|
|
if (lp->d_cylskew != 0) {
|
|
|
|
(void) fprintf(f, "%scs#%d:", did, lp->d_cylskew);
|
|
|
|
did = "";
|
|
|
|
}
|
|
|
|
if (lp->d_headswitch != 0) {
|
|
|
|
(void) fprintf(f, "%shs#%d:", did, lp->d_headswitch);
|
|
|
|
did = "";
|
|
|
|
}
|
|
|
|
if (lp->d_trkseek != 0) {
|
|
|
|
(void) fprintf(f, "%sts#%d:", did, lp->d_trkseek);
|
|
|
|
did = "";
|
|
|
|
}
|
|
|
|
#ifdef notyet
|
|
|
|
(void) fprintf(f, "drivedata: ");
|
|
|
|
for (i = NDDATA - 1; i >= 0; i--)
|
|
|
|
if (lp->d_drivedata[i])
|
|
|
|
break;
|
|
|
|
if (i < 0)
|
|
|
|
i = 0;
|
|
|
|
for (j = 0; j <= i; j++)
|
|
|
|
(void) fprintf(f, "%d ", lp->d_drivedata[j]);
|
2000-12-24 08:59:11 +03:00
|
|
|
#endif /* notyet */
|
1996-10-02 17:49:44 +04:00
|
|
|
pp = lp->d_partitions;
|
|
|
|
for (i = 0; i < lp->d_npartitions; i++, pp++) {
|
|
|
|
if (pp->p_size) {
|
|
|
|
char c = 'a' + i;
|
|
|
|
(void) fprintf(f, "\\\n\t:");
|
|
|
|
(void) fprintf(f, "p%c#%d:", c, pp->p_size);
|
|
|
|
(void) fprintf(f, "o%c#%d:", c, pp->p_offset);
|
|
|
|
if (pp->p_fstype != FS_UNUSED) {
|
|
|
|
if ((unsigned) pp->p_fstype < FSMAXTYPES)
|
2001-01-03 09:55:30 +03:00
|
|
|
(void) fprintf(f, "t%c=%s:", c,
|
1996-10-02 17:49:44 +04:00
|
|
|
fstypenames[pp->p_fstype]);
|
|
|
|
else
|
|
|
|
(void) fprintf(f, "t%c=unknown%d:",
|
|
|
|
c, pp->p_fstype);
|
|
|
|
}
|
|
|
|
switch (pp->p_fstype) {
|
|
|
|
|
|
|
|
case FS_UNUSED:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case FS_BSDFFS:
|
1999-06-04 01:15:49 +04:00
|
|
|
case FS_BSDLFS:
|
Make BSDLFS a EXT2FS-like filesystem, that is, dont print or parse the cpg
field.
According to disklabel.h, its LFS semantics are "segment shift" (log2(segment
size)), but in the code it is used nowhere, and there are even plans to
allow non-poweroftwo segment sizes, so it won't ever work.
While at this, simplify the disktab-like output routine... here, currently,
BSDFFS, BSDLFS, EX2FS and ADOS do the same, so don't duplicate the code.
1999-06-04 23:02:34 +04:00
|
|
|
case FS_EX2FS:
|
1999-06-04 01:15:49 +04:00
|
|
|
case FS_ADOS:
|
2002-09-28 04:47:24 +04:00
|
|
|
case FS_APPLEUFS:
|
1996-10-02 17:49:44 +04:00
|
|
|
(void) fprintf(f, "b%c#%d:", c,
|
|
|
|
pp->p_fsize * pp->p_frag);
|
|
|
|
(void) fprintf(f, "f%c#%d:", c, pp->p_fsize);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(void) fprintf(f, "\n");
|
|
|
|
(void) fflush(f);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
2005-10-20 01:22:21 +04:00
|
|
|
edit(int f)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1999-07-21 21:56:34 +04:00
|
|
|
const char *tmpdir;
|
2005-10-20 01:22:21 +04:00
|
|
|
char tmpfil[MAXPATHLEN];
|
2000-12-24 08:59:11 +03:00
|
|
|
int first, ch, fd;
|
2006-03-18 14:38:59 +03:00
|
|
|
int get_ok;
|
2000-12-24 08:59:11 +03:00
|
|
|
FILE *fp;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1999-07-21 21:56:34 +04:00
|
|
|
if ((tmpdir = getenv("TMPDIR")) == NULL)
|
|
|
|
tmpdir = _PATH_TMP;
|
2000-08-15 02:37:08 +04:00
|
|
|
(void)snprintf(tmpfil, sizeof(tmpfil), "%s/%s", tmpdir, TMPFILE);
|
1997-03-16 08:25:38 +03:00
|
|
|
if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warn("%s", tmpfil);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (1);
|
|
|
|
}
|
1997-03-16 08:25:38 +03:00
|
|
|
(void)fchmod(fd, 0600);
|
2005-10-20 01:22:21 +04:00
|
|
|
showinfo(fp, &lab, specname);
|
|
|
|
showpartitions(fp, &lab, Cflag);
|
1997-03-16 08:25:38 +03:00
|
|
|
(void) fclose(fp);
|
1993-03-21 12:45:37 +03:00
|
|
|
for (;;) {
|
2005-10-20 01:22:21 +04:00
|
|
|
if (!editit(tmpfil))
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
1997-03-16 08:25:38 +03:00
|
|
|
fp = fopen(tmpfil, "r");
|
|
|
|
if (fp == NULL) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warn("%s", tmpfil);
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
}
|
2005-10-20 01:22:21 +04:00
|
|
|
(void) memset(&lab, 0, sizeof(lab));
|
2006-03-18 14:38:59 +03:00
|
|
|
get_ok = getasciilabel(fp, &lab);
|
|
|
|
fclose(fp);
|
|
|
|
if (get_ok && write_label(f) == 0) {
|
|
|
|
(void) unlink(tmpfil);
|
|
|
|
return (0);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
1996-10-02 17:49:44 +04:00
|
|
|
(void) printf("re-edit the label? [y]: ");
|
|
|
|
(void) fflush(stdout);
|
1994-09-30 05:33:15 +03:00
|
|
|
first = ch = getchar();
|
|
|
|
while (ch != '\n' && ch != EOF)
|
|
|
|
ch = getchar();
|
|
|
|
if (first == 'n' || first == 'N')
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
|
|
|
}
|
1995-01-30 23:14:10 +03:00
|
|
|
(void)unlink(tmpfil);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
1996-10-02 17:49:44 +04:00
|
|
|
static int
|
2005-10-20 01:22:21 +04:00
|
|
|
editit(const char *tmpfil)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1994-09-30 05:33:15 +03:00
|
|
|
int pid, xpid;
|
2001-10-19 05:16:37 +04:00
|
|
|
int status;
|
2003-01-16 12:38:37 +03:00
|
|
|
sigset_t nsigset, osigset;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2003-01-16 12:38:37 +03:00
|
|
|
sigemptyset(&nsigset);
|
|
|
|
sigaddset(&nsigset, SIGINT);
|
|
|
|
sigaddset(&nsigset, SIGQUIT);
|
|
|
|
sigaddset(&nsigset, SIGHUP);
|
|
|
|
sigprocmask(SIG_BLOCK, &nsigset, &osigset);
|
1993-03-21 12:45:37 +03:00
|
|
|
while ((pid = fork()) < 0) {
|
|
|
|
if (errno != EAGAIN) {
|
1995-04-30 02:42:07 +04:00
|
|
|
sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
|
1994-09-23 02:03:52 +04:00
|
|
|
warn("fork");
|
|
|
|
return (0);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
sleep(1);
|
|
|
|
}
|
|
|
|
if (pid == 0) {
|
2000-05-27 23:01:13 +04:00
|
|
|
const char *ed;
|
|
|
|
char *buf;
|
|
|
|
int retval;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
1995-04-30 02:42:07 +04:00
|
|
|
sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
|
1993-03-21 12:45:37 +03:00
|
|
|
setgid(getgid());
|
|
|
|
setuid(getuid());
|
|
|
|
if ((ed = getenv("EDITOR")) == (char *)0)
|
|
|
|
ed = DEFEDITOR;
|
2000-05-27 23:01:13 +04:00
|
|
|
/*
|
2002-12-06 01:59:25 +03:00
|
|
|
* Jump through a few extra hoops in case someone's editor
|
|
|
|
* is "editor arg1 arg2".
|
2000-05-27 23:01:13 +04:00
|
|
|
*/
|
|
|
|
asprintf(&buf, "%s %s", ed, tmpfil);
|
2003-07-13 11:48:01 +04:00
|
|
|
if (!buf)
|
|
|
|
err(1, "malloc");
|
2002-12-06 01:59:25 +03:00
|
|
|
retval = execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", buf, NULL);
|
2000-05-27 23:01:13 +04:00
|
|
|
if (retval == -1)
|
|
|
|
perror(ed);
|
|
|
|
exit(retval);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2001-10-19 05:16:37 +04:00
|
|
|
while ((xpid = wait(&status)) >= 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
if (xpid == pid)
|
|
|
|
break;
|
1995-04-30 02:42:07 +04:00
|
|
|
sigprocmask(SIG_SETMASK, &osigset, (sigset_t *)0);
|
2001-10-19 05:16:37 +04:00
|
|
|
return (!status);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
1996-10-02 17:49:44 +04:00
|
|
|
static char *
|
2000-12-24 08:59:11 +03:00
|
|
|
skip(char *cp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
|
|
|
|
1994-09-30 05:33:15 +03:00
|
|
|
cp += strspn(cp, " \t");
|
|
|
|
if (*cp == '\0')
|
|
|
|
return (NULL);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (cp);
|
|
|
|
}
|
|
|
|
|
1996-10-02 17:49:44 +04:00
|
|
|
static char *
|
2000-12-24 08:59:11 +03:00
|
|
|
word(char *cp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2000-12-24 08:59:11 +03:00
|
|
|
|
1996-08-10 22:54:48 +04:00
|
|
|
if (cp == NULL || *cp == '\0')
|
|
|
|
return (NULL);
|
1994-09-30 05:33:15 +03:00
|
|
|
|
|
|
|
cp += strcspn(cp, " \t");
|
|
|
|
if (*cp == '\0')
|
|
|
|
return (NULL);
|
|
|
|
*cp++ = '\0';
|
|
|
|
cp += strspn(cp, " \t");
|
|
|
|
if (*cp == '\0')
|
|
|
|
return (NULL);
|
|
|
|
return (cp);
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
|
2004-03-14 01:04:37 +03:00
|
|
|
#define _CHECKLINE \
|
|
|
|
if (tp == NULL || *tp == '\0') { \
|
|
|
|
warnx("line %d: too few fields", lineno); \
|
|
|
|
errors++; \
|
|
|
|
break; \
|
|
|
|
}
|
|
|
|
|
|
|
|
#define __CHECKLINE \
|
|
|
|
if (*tp == NULL || **tp == '\0') { \
|
|
|
|
warnx("line %d: too few fields", lineno); \
|
|
|
|
*tp = _error_; \
|
|
|
|
return 0; \
|
|
|
|
}
|
|
|
|
|
|
|
|
static char _error_[] = "";
|
|
|
|
#define NXTNUM(n) if ((n = nxtnum(&tp, lineno),0) + tp != _error_) \
|
|
|
|
; else goto error
|
|
|
|
#define NXTXNUM(n) if ((n = nxtxnum(&tp, lp, lineno),0) + tp != _error_) \
|
|
|
|
; else goto error
|
|
|
|
|
|
|
|
static unsigned long
|
|
|
|
nxtnum(char **tp, int lineno)
|
|
|
|
{
|
|
|
|
char *cp;
|
|
|
|
unsigned long v;
|
|
|
|
|
|
|
|
__CHECKLINE
|
2004-03-14 03:39:53 +03:00
|
|
|
if (getulong(*tp, '\0', &cp, &v, UINT32_MAX) != 0) {
|
2004-03-14 01:04:37 +03:00
|
|
|
warnx("line %d: syntax error", lineno);
|
|
|
|
*tp = _error_;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
*tp = cp;
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static unsigned long
|
|
|
|
nxtxnum(char **tp, struct disklabel *lp, int lineno)
|
|
|
|
{
|
|
|
|
char *cp, *ncp;
|
2004-03-14 03:39:53 +03:00
|
|
|
unsigned long n, v;
|
2004-03-14 01:04:37 +03:00
|
|
|
|
|
|
|
__CHECKLINE
|
|
|
|
cp = *tp;
|
2004-03-14 03:39:53 +03:00
|
|
|
if (getulong(cp, '/', &ncp, &n, UINT32_MAX) != 0)
|
|
|
|
goto bad;
|
|
|
|
|
|
|
|
if (*ncp == '/') {
|
2004-03-14 01:04:37 +03:00
|
|
|
n *= lp->d_secpercyl;
|
|
|
|
cp = ncp + 1;
|
2004-03-14 03:39:53 +03:00
|
|
|
if (getulong(cp, '/', &ncp, &v, UINT32_MAX) != 0)
|
|
|
|
goto bad;
|
|
|
|
n += v * lp->d_nsectors;
|
|
|
|
cp = ncp + 1;
|
|
|
|
if (getulong(cp, '\0', &ncp, &v, UINT32_MAX) != 0)
|
|
|
|
goto bad;
|
|
|
|
n += v;
|
2004-03-14 01:04:37 +03:00
|
|
|
}
|
|
|
|
*tp = ncp;
|
|
|
|
return n;
|
2004-03-14 03:39:53 +03:00
|
|
|
bad:
|
|
|
|
warnx("line %d: invalid format", lineno);
|
|
|
|
*tp = _error_;
|
|
|
|
return 0;
|
2004-03-14 01:04:37 +03:00
|
|
|
}
|
|
|
|
|
1993-03-21 12:45:37 +03:00
|
|
|
/*
|
|
|
|
* Read an ascii label in from fd f,
|
1999-05-03 13:45:01 +04:00
|
|
|
* in the same format as that put out by showinfo() and showpartitions(),
|
1993-03-21 12:45:37 +03:00
|
|
|
* and fill in lp.
|
|
|
|
*/
|
1996-10-02 17:49:44 +04:00
|
|
|
static int
|
2000-12-24 08:59:11 +03:00
|
|
|
getasciilabel(FILE *f, struct disklabel *lp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1998-07-26 16:00:43 +04:00
|
|
|
const char *const *cpp, *s;
|
1994-09-30 05:33:15 +03:00
|
|
|
struct partition *pp;
|
2001-10-19 05:16:37 +04:00
|
|
|
char *cp, *tp, line[BUFSIZ], tbuf[15];
|
2004-03-01 00:31:14 +03:00
|
|
|
int lineno, errors;
|
|
|
|
unsigned long v;
|
2004-03-14 01:04:37 +03:00
|
|
|
unsigned int part;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2000-12-24 08:59:11 +03:00
|
|
|
lineno = 0;
|
|
|
|
errors = 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
lp->d_bbsize = BBSIZE; /* XXX */
|
2003-04-02 14:39:19 +04:00
|
|
|
lp->d_sbsize = SBLOCKSIZE; /* XXX */
|
1993-03-21 12:45:37 +03:00
|
|
|
while (fgets(line, sizeof(line) - 1, f)) {
|
|
|
|
lineno++;
|
1996-10-02 17:49:44 +04:00
|
|
|
if ((cp = strpbrk(line, "#\r\n")) != NULL)
|
1993-03-21 12:45:37 +03:00
|
|
|
*cp = '\0';
|
|
|
|
cp = skip(line);
|
1996-08-10 22:54:48 +04:00
|
|
|
if (cp == NULL) /* blank line or comment line */
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
1996-08-10 22:54:48 +04:00
|
|
|
tp = strchr(cp, ':'); /* everything has a colon in it */
|
1993-03-21 12:45:37 +03:00
|
|
|
if (tp == NULL) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: syntax error", lineno);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
*tp++ = '\0', tp = skip(tp);
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "type")) {
|
2001-10-19 05:16:37 +04:00
|
|
|
if (tp == NULL) {
|
|
|
|
strlcpy(tbuf, "unknown", sizeof(tbuf));
|
|
|
|
tp = tbuf;
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
cpp = dktypenames;
|
|
|
|
for (; cpp < &dktypenames[DKMAXTYPES]; cpp++)
|
2000-08-15 02:37:08 +04:00
|
|
|
if ((s = *cpp) && !strcasecmp(s, tp)) {
|
1993-03-21 12:45:37 +03:00
|
|
|
lp->d_type = cpp - dktypenames;
|
|
|
|
goto next;
|
|
|
|
}
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM16(tp, &v) != 0) {
|
2004-03-01 00:31:14 +03:00
|
|
|
warnx("line %d: syntax error", lineno);
|
|
|
|
errors++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (v >= DKMAXTYPES)
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: warning, unknown disk type: %s",
|
|
|
|
lineno, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
lp->d_type = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "flags")) {
|
1993-03-21 12:45:37 +03:00
|
|
|
for (v = 0; (cp = tp) && *cp != '\0';) {
|
|
|
|
tp = word(cp);
|
2000-08-15 02:37:08 +04:00
|
|
|
if (!strcasecmp(cp, "removable"))
|
1993-03-21 12:45:37 +03:00
|
|
|
v |= D_REMOVABLE;
|
2000-08-15 02:37:08 +04:00
|
|
|
else if (!strcasecmp(cp, "ecc"))
|
1993-03-21 12:45:37 +03:00
|
|
|
v |= D_ECC;
|
2000-08-15 02:37:08 +04:00
|
|
|
else if (!strcasecmp(cp, "badsect"))
|
1993-03-21 12:45:37 +03:00
|
|
|
v |= D_BADSECT;
|
|
|
|
else {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad flag: %s",
|
1993-03-21 12:45:37 +03:00
|
|
|
lineno, cp);
|
|
|
|
errors++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lp->d_flags = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "drivedata")) {
|
|
|
|
int i;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
|
|
|
for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(cp, &v) != 0) {
|
2004-03-01 00:31:14 +03:00
|
|
|
warnx("line %d: bad drive data",
|
|
|
|
lineno);
|
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_drivedata[i] = v;
|
|
|
|
i++;
|
1993-03-21 12:45:37 +03:00
|
|
|
tp = word(cp);
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2004-03-01 00:31:14 +03:00
|
|
|
if (sscanf(cp, "%lu partitions", &v) == 1) {
|
|
|
|
if (v == 0 || v > MAXPARTITIONS) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad # of partitions", lineno);
|
1993-03-21 12:45:37 +03:00
|
|
|
lp->d_npartitions = MAXPARTITIONS;
|
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_npartitions = v;
|
|
|
|
continue;
|
|
|
|
}
|
2001-10-19 05:16:37 +04:00
|
|
|
if (tp == NULL) {
|
|
|
|
tbuf[0] = '\0';
|
|
|
|
tp = tbuf;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "disk")) {
|
2000-08-15 02:37:08 +04:00
|
|
|
strncpy(lp->d_typename, tp, sizeof(lp->d_typename));
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "label")) {
|
2000-08-15 02:37:08 +04:00
|
|
|
strncpy(lp->d_packname, tp, sizeof(lp->d_packname));
|
1993-03-21 12:45:37 +03:00
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "bytes/sector")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(tp, &v) != 0 || v <= 0 || (v % 512) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_secsize = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "sectors/track")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_nsectors = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "sectors/cylinder")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_secpercyl = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "tracks/cylinder")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_ntracks = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "cylinders")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_ncylinders = v;
|
|
|
|
continue;
|
|
|
|
}
|
1996-03-14 22:49:24 +03:00
|
|
|
if (!strcmp(cp, "total sectors")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(tp, &v) != 0) {
|
1996-03-14 22:49:24 +03:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_secperunit = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "rpm")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM16(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_rpm = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "interleave")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM16(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_interleave = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "trackskew")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM16(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_trackskew = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "cylinderskew")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM16(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_cylskew = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "headswitch")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_headswitch = v;
|
|
|
|
continue;
|
|
|
|
}
|
1994-09-30 05:33:15 +03:00
|
|
|
if (!strcmp(cp, "track-to-track seek")) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM32(tp, &v) != 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("line %d: bad %s: %s", lineno, cp, tp);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else
|
|
|
|
lp->d_trkseek = v;
|
|
|
|
continue;
|
|
|
|
}
|
2004-03-14 01:04:37 +03:00
|
|
|
if ('a' > *cp || *cp > 'z' || cp[1] != '\0') {
|
|
|
|
warnx("line %d: unknown field: %s", lineno, cp);
|
|
|
|
errors++;
|
|
|
|
continue;
|
|
|
|
}
|
2000-12-24 08:59:11 +03:00
|
|
|
|
2004-03-14 01:04:37 +03:00
|
|
|
/* We have a partition entry */
|
|
|
|
part = *cp - 'a';
|
2000-12-24 08:59:11 +03:00
|
|
|
|
2004-06-22 22:32:45 +04:00
|
|
|
if (part >= MAXPARTITIONS) {
|
2004-03-14 01:04:37 +03:00
|
|
|
warnx("line %d: bad partition name: %s", lineno, cp);
|
|
|
|
errors++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
pp = &lp->d_partitions[part];
|
|
|
|
|
|
|
|
NXTXNUM(pp->p_size);
|
|
|
|
NXTXNUM(pp->p_offset);
|
|
|
|
/* can't use word() here because of blanks in fstypenames[] */
|
|
|
|
tp += strspn(tp, " \t");
|
|
|
|
_CHECKLINE
|
|
|
|
cp = tp;
|
|
|
|
cpp = fstypenames;
|
|
|
|
for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) {
|
|
|
|
s = *cpp;
|
|
|
|
if (s == NULL ||
|
|
|
|
(cp[strlen(s)] != ' ' &&
|
|
|
|
cp[strlen(s)] != '\t' &&
|
|
|
|
cp[strlen(s)] != '\0'))
|
|
|
|
continue;
|
|
|
|
if (!memcmp(s, cp, strlen(s))) {
|
|
|
|
pp->p_fstype = cpp - fstypenames;
|
|
|
|
tp += strlen(s);
|
|
|
|
if (*tp == '\0')
|
|
|
|
tp = NULL;
|
|
|
|
else {
|
|
|
|
tp += strspn(tp, " \t");
|
1997-10-13 13:53:26 +04:00
|
|
|
if (*tp == '\0')
|
|
|
|
tp = NULL;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2004-03-14 01:04:37 +03:00
|
|
|
goto gottype;
|
1997-10-13 13:53:26 +04:00
|
|
|
}
|
2004-03-14 01:04:37 +03:00
|
|
|
}
|
|
|
|
tp = word(cp);
|
|
|
|
if (isdigit(*cp & 0xff)) {
|
2004-03-14 03:39:53 +03:00
|
|
|
if (GETNUM8(cp, &v) != 0) {
|
2004-03-14 01:04:37 +03:00
|
|
|
warnx("line %d: syntax error", lineno);
|
|
|
|
errors++;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2004-03-14 01:04:37 +03:00
|
|
|
} else
|
|
|
|
v = FSMAXTYPES;
|
|
|
|
if ((unsigned)v >= FSMAXTYPES) {
|
|
|
|
warnx("line %d: warning, unknown filesystem type: %s",
|
|
|
|
lineno, cp);
|
|
|
|
v = FS_UNUSED;
|
|
|
|
}
|
|
|
|
pp->p_fstype = v;
|
|
|
|
gottype:
|
|
|
|
switch (pp->p_fstype) {
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2004-03-14 01:04:37 +03:00
|
|
|
case FS_UNUSED: /* XXX */
|
|
|
|
NXTNUM(pp->p_fsize);
|
|
|
|
if (pp->p_fsize == 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
2004-03-14 01:04:37 +03:00
|
|
|
NXTNUM(v);
|
|
|
|
pp->p_frag = v / pp->p_fsize;
|
|
|
|
break;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2004-03-14 01:04:37 +03:00
|
|
|
case FS_BSDFFS:
|
|
|
|
case FS_ADOS:
|
|
|
|
case FS_APPLEUFS:
|
|
|
|
NXTNUM(pp->p_fsize);
|
|
|
|
if (pp->p_fsize == 0)
|
1997-10-13 13:53:26 +04:00
|
|
|
break;
|
2004-03-14 01:04:37 +03:00
|
|
|
NXTNUM(v);
|
|
|
|
pp->p_frag = v / pp->p_fsize;
|
|
|
|
NXTNUM(pp->p_cpg);
|
|
|
|
break;
|
|
|
|
case FS_BSDLFS:
|
|
|
|
NXTNUM(pp->p_fsize);
|
|
|
|
if (pp->p_fsize == 0)
|
2002-05-27 21:33:08 +04:00
|
|
|
break;
|
2004-03-14 01:04:37 +03:00
|
|
|
NXTNUM(v);
|
|
|
|
pp->p_frag = v / pp->p_fsize;
|
|
|
|
NXTNUM(pp->p_sgs);
|
|
|
|
break;
|
|
|
|
case FS_EX2FS:
|
|
|
|
NXTNUM(pp->p_fsize);
|
|
|
|
if (pp->p_fsize == 0)
|
1993-03-21 12:45:37 +03:00
|
|
|
break;
|
2004-03-14 01:04:37 +03:00
|
|
|
NXTNUM(v);
|
|
|
|
pp->p_frag = v / pp->p_fsize;
|
|
|
|
break;
|
|
|
|
case FS_ISO9660:
|
|
|
|
NXTNUM(pp->p_cdsession);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
2004-03-14 01:04:37 +03:00
|
|
|
continue;
|
|
|
|
error:
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
2000-12-24 08:59:11 +03:00
|
|
|
next:
|
1993-03-21 12:45:37 +03:00
|
|
|
;
|
|
|
|
}
|
|
|
|
errors += checklabel(lp);
|
|
|
|
return (errors == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Check disklabel for errors and fill in
|
|
|
|
* derived fields according to supplied values.
|
|
|
|
*/
|
1997-03-09 02:46:08 +03:00
|
|
|
int
|
2000-12-24 08:59:11 +03:00
|
|
|
checklabel(struct disklabel *lp)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
2004-07-14 01:23:13 +04:00
|
|
|
struct partition *pp, *qp;
|
|
|
|
int i, j, errors;
|
2000-12-24 08:59:11 +03:00
|
|
|
char part;
|
1993-03-21 12:45:37 +03:00
|
|
|
|
2000-12-24 08:59:11 +03:00
|
|
|
errors = 0;
|
1993-03-21 12:45:37 +03:00
|
|
|
if (lp->d_secsize == 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("sector size %d", lp->d_secsize);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
if (lp->d_nsectors == 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("sectors/track %d", lp->d_nsectors);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
if (lp->d_ntracks == 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("tracks/cylinder %d", lp->d_ntracks);
|
1993-03-21 12:45:37 +03:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
if (lp->d_ncylinders == 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("cylinders/unit %d", lp->d_ncylinders);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
}
|
|
|
|
if (lp->d_rpm == 0)
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("warning, revolutions/minute %d", lp->d_rpm);
|
1993-03-21 12:45:37 +03:00
|
|
|
if (lp->d_secpercyl == 0)
|
|
|
|
lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
|
|
|
|
if (lp->d_secperunit == 0)
|
|
|
|
lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders;
|
|
|
|
if (lp->d_bbsize == 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("boot block size %d", lp->d_bbsize);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else if (lp->d_bbsize % lp->d_secsize)
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("warning, boot block size %% sector-size != 0");
|
1993-03-21 12:45:37 +03:00
|
|
|
if (lp->d_sbsize == 0) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("super block size %d", lp->d_sbsize);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
} else if (lp->d_sbsize % lp->d_secsize)
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("warning, super block size %% sector-size != 0");
|
1993-03-21 12:45:37 +03:00
|
|
|
if (lp->d_npartitions > MAXPARTITIONS)
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("warning, number of partitions (%d) > MAXPARTITIONS (%d)",
|
1993-03-21 12:45:37 +03:00
|
|
|
lp->d_npartitions, MAXPARTITIONS);
|
2004-06-22 22:32:45 +04:00
|
|
|
else
|
|
|
|
for (i = MAXPARTITIONS - 1; i >= lp->d_npartitions; i--) {
|
2004-06-24 07:13:00 +04:00
|
|
|
part = 'a' + i;
|
2004-06-22 22:32:45 +04:00
|
|
|
pp = &lp->d_partitions[i];
|
|
|
|
if (pp->p_size || pp->p_offset) {
|
2004-06-24 07:13:00 +04:00
|
|
|
warnx("warning, partition %c increased "
|
|
|
|
"number of partitions from %d to %d",
|
|
|
|
part, lp->d_npartitions, i + 1);
|
2004-06-22 22:32:45 +04:00
|
|
|
lp->d_npartitions = i + 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
for (i = 0; i < lp->d_npartitions; i++) {
|
2004-06-24 07:13:00 +04:00
|
|
|
part = 'a' + i;
|
1993-03-21 12:45:37 +03:00
|
|
|
pp = &lp->d_partitions[i];
|
|
|
|
if (pp->p_size == 0 && pp->p_offset != 0)
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("warning, partition %c: size 0, but offset %d",
|
1993-03-21 12:45:37 +03:00
|
|
|
part, pp->p_offset);
|
1999-01-21 14:58:00 +03:00
|
|
|
#ifdef STRICT_CYLINDER_ALIGNMENT
|
|
|
|
if (pp->p_offset % lp->d_secpercyl) {
|
1998-08-04 15:52:52 +04:00
|
|
|
warnx("warning, partition %c:"
|
2004-11-12 04:00:40 +03:00
|
|
|
" not starting on cylinder boundary",
|
1993-03-21 12:45:37 +03:00
|
|
|
part);
|
1999-01-21 14:58:00 +03:00
|
|
|
errors++;
|
|
|
|
}
|
2000-12-24 08:59:11 +03:00
|
|
|
#endif /* STRICT_CYLINDER_ALIGNMENT */
|
1993-03-21 12:45:37 +03:00
|
|
|
if (pp->p_offset > lp->d_secperunit) {
|
1994-09-23 02:03:52 +04:00
|
|
|
warnx("partition %c: offset past end of unit", part);
|
1993-03-21 12:45:37 +03:00
|
|
|
errors++;
|
|
|
|
}
|
|
|
|
if (pp->p_offset + pp->p_size > lp->d_secperunit) {
|
1998-08-04 15:52:52 +04:00
|
|
|
warnx("partition %c: partition extends"
|
2004-06-24 07:13:00 +04:00
|
|
|
" past end of unit",
|
1993-03-21 12:45:37 +03:00
|
|
|
part);
|
|
|
|
errors++;
|
|
|
|
}
|
2004-07-14 01:23:13 +04:00
|
|
|
if (pp->p_fstype != FS_UNUSED)
|
|
|
|
for (j = i + 1; j < lp->d_npartitions; j++) {
|
|
|
|
qp = &lp->d_partitions[j];
|
|
|
|
if (qp->p_fstype == FS_UNUSED)
|
|
|
|
continue;
|
|
|
|
if (pp->p_offset < qp->p_offset + qp->p_size &&
|
|
|
|
qp->p_offset < pp->p_offset + pp->p_size)
|
|
|
|
warnx("partitions %c and %c overlap",
|
|
|
|
part, 'a' + j);
|
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
}
|
|
|
|
return (errors);
|
|
|
|
}
|
|
|
|
|
1996-10-02 17:49:44 +04:00
|
|
|
static void
|
2000-12-24 08:59:11 +03:00
|
|
|
usage(void)
|
1993-03-21 12:45:37 +03:00
|
|
|
{
|
1996-10-02 17:49:44 +04:00
|
|
|
static const struct {
|
2001-10-19 05:16:37 +04:00
|
|
|
const char *name;
|
|
|
|
const char *expn;
|
1996-10-02 17:49:44 +04:00
|
|
|
} usages[] = {
|
2005-10-20 01:22:21 +04:00
|
|
|
{ "[-ACFrtv] disk", "(to read label)" },
|
|
|
|
{ "-w [-DFrv] [-f disktab] disk disktype [packid]", "(to write label)" },
|
|
|
|
{ "-e [-CDFIrv] disk", "(to edit label)" },
|
|
|
|
{ "-i [-DFIrv] disk", "(to create a label interactively)" },
|
|
|
|
{ "-D [-v] disk", "(to delete existing label(s))" },
|
|
|
|
{ "-R [-DFrv] disk protofile", "(to restore label)" },
|
2005-06-18 01:20:18 +04:00
|
|
|
{ "[-NW] disk", "(to write disable/enable label)" },
|
|
|
|
{ NULL, NULL }
|
1998-01-01 07:38:43 +03:00
|
|
|
};
|
1996-10-02 17:49:44 +04:00
|
|
|
int i;
|
2005-06-18 01:20:18 +04:00
|
|
|
const char *pn = getprogname();
|
|
|
|
const char *t = "usage:";
|
1996-10-02 17:49:44 +04:00
|
|
|
|
2005-06-18 01:20:18 +04:00
|
|
|
for (i = 0; usages[i].name != NULL; i++) {
|
|
|
|
(void)fprintf(stderr, "%s %s %s\n\t%s\n",
|
|
|
|
t, pn, usages[i].name, usages[i].expn);
|
|
|
|
t = "or";
|
1996-10-02 17:49:44 +04:00
|
|
|
}
|
1993-03-21 12:45:37 +03:00
|
|
|
exit(1);
|
|
|
|
}
|
2004-03-01 00:31:14 +03:00
|
|
|
|
|
|
|
static int
|
2004-03-14 03:39:53 +03:00
|
|
|
getulong(const char *str, char sep, char **epp, unsigned long *ul,
|
|
|
|
unsigned long max)
|
2004-03-01 00:31:14 +03:00
|
|
|
{
|
|
|
|
char *ep;
|
|
|
|
|
2004-03-14 03:39:53 +03:00
|
|
|
if (epp == NULL)
|
|
|
|
epp = &ep;
|
|
|
|
|
|
|
|
*ul = strtoul(str, epp, 10);
|
|
|
|
|
|
|
|
if ((*ul == ULONG_MAX && errno == ERANGE) || *ul > max)
|
2004-03-01 00:31:14 +03:00
|
|
|
return ERANGE;
|
2004-03-14 03:39:53 +03:00
|
|
|
|
|
|
|
if (*str == '\0' || (**epp != '\0' && **epp != sep &&
|
|
|
|
!isspace((unsigned char)**epp)))
|
|
|
|
return EFTYPE;
|
|
|
|
|
|
|
|
return 0;
|
2004-03-01 00:31:14 +03:00
|
|
|
}
|