#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <paths.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/disklabel.h>
#include "disk.h"
#include "user.h"
#include "auto.h"
#define _PATH_MBR "/usr/standalone/i386/boot0"
void
usage()
{
extern char * __progname;
fprintf(stderr, "usage: %s "
"[-ieu] [-f mbrboot] [-c cyl -h head -s sect] [-S size] [-r] [-a style] disk\n"
"\t-i: initialize disk with new MBR\n"
"\t-u: update MBR code, preserve partition table\n"
"\t-e: edit MBRs on disk interactively\n"
"\t-f: specify non-standard MBR template\n"
"\t-chs: specify disk geometry\n"
"\t-S: specify disk size\n"
"\t-r: read partition specs from stdin (implies -i)\n"
"\t-a: auto-partition with the given style\n"
"\t-d: dump partition table\n"
"\t-y: don't ask any questions\n"
"\t-t: test if disk is partitioned\n"
"`disk' is of the form /dev/rdisk0.\n",
__progname);
fprintf(stderr, "auto-partition styles:\n");
AUTO_print_styles(stderr);
exit(1);
}
char *mbr_binary = NULL;
int
main(argc, argv)
int argc;
char **argv;
{
int ch, fd;
int i_flag = 0, m_flag = 0, u_flag = 0, r_flag = 0, d_flag = 0, y_flag = 0, t_flag = 0;
int c_arg = 0, h_arg = 0, s_arg = 0;
int size_arg = 0;
disk_t disk;
DISK_metrics *usermetrics;
char *mbrfile = _PATH_MBR;
mbr_t *mp;
char *auto_style = NULL;
while ((ch = getopt(argc, argv, "ieuf:c:h:s:S:ra:dyt")) != -1) {
switch(ch) {
case 'i':
i_flag = 1;
break;
case 'u':
u_flag = 1;
break;
case 'e':
m_flag = 1;
break;
case 'f':
mbrfile = optarg;
break;
case 'c':
c_arg = atoi(optarg);
if (c_arg < 1 || c_arg > 262144)
errx(1, "Cylinder argument out of range.");
break;
case 'h':
h_arg = atoi(optarg);
if (h_arg < 1 || h_arg > 256)
errx(1, "Head argument out of range.");
break;
case 's':
s_arg = atoi(optarg);
if (s_arg < 1 || s_arg > 63)
errx(1, "Sector argument out of range.");
break;
case 'S':
size_arg = atoi(optarg);
break;
case 'r':
r_flag = 1;
break;
case 'a':
auto_style = optarg;
break;
case 'd':
d_flag = 1;
break;
case 'y':
y_flag = 1;
break;
case 't':
t_flag = 1;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc != 1)
usage();
else
disk.name = argv[0];
if (i_flag && u_flag) errx(1, "-i and -u cannot be specified simultaneously");
if (c_arg | h_arg | s_arg | size_arg) {
usermetrics = malloc(sizeof(DISK_metrics));
if (usermetrics != NULL) {
if (c_arg && h_arg && s_arg) {
usermetrics->cylinders = c_arg;
usermetrics->heads = h_arg;
usermetrics->sectors = s_arg;
if (size_arg) {
usermetrics->size = size_arg;
} else {
usermetrics->size = c_arg * h_arg * s_arg;
}
} else {
if (size_arg) {
usermetrics->size = size_arg;
DISK_fake_CHS(usermetrics);
} else {
errx(1, "Please specify a full geometry with [-chs].");
}
}
}
} else {
usermetrics = NULL;
}
disk.real = NULL;
if (DISK_getmetrics(&disk, usermetrics))
errx(1, "Can't get disk geometry, please use [-chs] to specify.");
if (t_flag) {
mbr_t *mbr;
mp = mbr = MBR_read_all(&disk);
while (mp) {
if (mp->signature != MBR_SIGNATURE) {
MBR_free(mbr);
exit(1);
}
mp = mp->next;
}
MBR_free(mbr);
exit(0);
}
if ((i_flag + r_flag + u_flag + m_flag) == 0) {
exit(USER_print_disk(&disk, d_flag));
}
if (auto_style && r_flag) {
errx(1, "Can't specify both -r and -a");
}
mbr_binary = (char *)malloc(MBR_CODE_SIZE);
if ((fd = open(mbrfile, O_RDONLY)) == -1) {
warn("could not open MBR file %s", mbrfile);
bzero(mbr_binary, MBR_CODE_SIZE);
} else {
int cc;
cc = read(fd, mbr_binary, MBR_CODE_SIZE);
if (cc < MBR_CODE_SIZE) {
err(1, "could not read MBR code");
}
close(fd);
}
if (u_flag) {
mp = MBR_read_all(&disk);
bcopy(mbr_binary, mp->code, MBR_CODE_SIZE);
MBR_make(mp);
} else if (i_flag) {
mp = MBR_alloc(NULL);
if (AUTO_init(&disk, auto_style, mp) != AUTO_OK) {
errx(1, "error initializing disk");
}
bcopy(mbr_binary, mp->code, MBR_CODE_SIZE);
MBR_make(mp);
} else if (r_flag) {
mp = MBR_parse_spec(stdin, &disk);
bcopy(mbr_binary, mp->code, MBR_CODE_SIZE);
MBR_make(mp);
} else {
mp = MBR_read_all(&disk);
}
if (i_flag || r_flag || u_flag) {
USER_write(&disk, mp, u_flag, y_flag);
}
if (m_flag) {
USER_modify(&disk, mp, 0, 0);
}
if (mbr_binary)
free(mbr_binary);
return (0);
}