Home | History | Annotate | Line # | Download | only in edlabel
      1 /*	$NetBSD: edlabel.c,v 1.1 2010/03/10 23:16:16 abs Exp $	*/
      2 
      3 /*
      4  * Copyright (c) 1995 Gordon W. Ross
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     21  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     22  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     23  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     25  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     26  */
     27 
     28 #include <sys/cdefs.h>
     29 #include <sys/types.h>
     30 #include <sys/param.h>
     31 #include <sys/ioctl.h>
     32 #define FSTYPENAMES
     33 #include <sys/disklabel.h>
     34 
     35 #include <fcntl.h>
     36 #include <stdio.h>
     37 #include <ctype.h>
     38 #include <string.h>
     39 #include <errno.h>
     40 #include <unistd.h>
     41 #include <util.h>
     42 #include <stdlib.h>
     43 
     44 /*
     45  * Machine dependent constants you want to retrieve only once...
     46  */
     47 int rawpartition, maxpartitions;
     48 
     49 /*
     50  * This is a data-driven program
     51  */
     52 struct field {
     53 	const char *f_name;
     54 	int f_offset;
     55 	int f_type;	/* 1:char, 2:short, 4:int, >4:string */
     56 };
     57 
     58 /* Table describing fields in the head of a disklabel. */
     59 #define	dloff(f) (int)(&((struct disklabel *)0)->f)
     60 struct field label_head[] = {
     61   { "        type_num", dloff(d_type), 2 },
     62   { "        sub_type", dloff(d_subtype), 2 },
     63   { "       type_name", dloff(d_typename), 16 },
     64   { "       pack_name", dloff(d_packname),  16 },
     65   { "    bytes/sector", dloff(d_secsize), 4 },
     66   { "   sectors/track", dloff(d_nsectors), 4 },
     67   { " tracks/cylinder", dloff(d_ntracks),  4 },
     68   { "       cylinders", dloff(d_ncylinders), 4 },
     69   { "sectors/cylinder", dloff(d_secpercyl), 4 },
     70   /* Don't care about the others until later... */
     71   { .f_name = NULL },
     72 };
     73 #undef dloff
     74 
     75 void	check_divisors(struct disklabel *);
     76 u_short	dkcksum(struct disklabel *);
     77 void	edit_geo(struct disklabel *);
     78 void	edit_head_all(struct disklabel *, int);
     79 void	edit_head_field(void *, struct field *, int);
     80 void	edit_partition(struct disklabel *, int, int);
     81 void	get_fstype(char *, u_int8_t *);
     82 void	get_val_cts(struct disklabel *, char *, u_int32_t *);
     83 void	label_modify(struct disklabel *, char *);
     84 void	label_print(struct disklabel *, char *);
     85 void	label_quit(struct disklabel *, char *);
     86 void	label_read(struct disklabel *, char *);
     87 void	label_write(struct disklabel *, char *);
     88 void	menu(void);
     89 void	print_val_cts(struct disklabel *, u_long val);
     90 
     91 char	tmpbuf[64];
     92 
     93 void
     94 edit_head_field(void *v, struct field *f, int modify /* also modify */)
     95 {
     96 	u_int8_t  *cp;
     97 	u_int tmp;
     98 
     99 	cp = v;
    100 	cp += f->f_offset;
    101 
    102 	printf("%s: ", f->f_name);
    103 
    104 	/* Print current value... */
    105 	switch (f->f_type) {
    106 	case 1:
    107 		tmp = *cp;
    108 		printf("%d", tmp);
    109 		break;
    110 	case 2:
    111 		tmp = *((u_int16_t *)cp);
    112 		printf("%d", tmp);
    113 		break;
    114 	case 4:
    115 		tmp = *((u_int32_t *)cp);
    116 		printf("%d", tmp);
    117 		break;
    118 
    119 	default:
    120 		/* must be a string. */
    121 		strlcpy(tmpbuf, (char*)cp, sizeof(tmpbuf));
    122 		printf("%s", tmpbuf);
    123 		break;
    124 	}
    125 
    126 	if (modify == 0) {
    127 		printf("\n");
    128 		return;
    129 	}
    130 	printf(" ? ");
    131 	fflush(stdout);
    132 
    133 	tmpbuf[0] = '\0';
    134 	if (fgets(tmpbuf, sizeof(tmpbuf), stdin) == NULL)
    135 		return;
    136 	if ((tmpbuf[0] == '\0') || (tmpbuf[0] == '\n')) {
    137 		/* no new value supplied. */
    138 		return;
    139 	}
    140 
    141 	/* store new value */
    142 	if (f->f_type <= 4)
    143 		if (sscanf(tmpbuf, "%d", &tmp) != 1)
    144 			return;
    145 
    146 	switch (f->f_type) {
    147 	case 1:
    148 		*cp = tmp;
    149 		break;
    150 	case 2:
    151 		*((u_int16_t *)cp) = tmp;
    152 		break;
    153 	case 4:
    154 		*((u_int32_t *)cp) = tmp;
    155 		break;
    156 	default:
    157 		/* Get rid of the trailing newline. */
    158 		tmp = strlen(tmpbuf);
    159 		if (tmp < 1)
    160 			break;
    161 		if (tmpbuf[tmp-1] == '\n')
    162 			tmpbuf[tmp-1] = '\0';
    163 		strncpy((char*)cp, tmpbuf, f->f_type);
    164 		break;
    165 	}
    166 }
    167 
    168 void
    169 edit_head_all(struct disklabel *d, int modify)
    170 {
    171 	struct field *f;
    172 
    173 	/* Edit head stuff. */
    174 	for (f = label_head; f->f_name; f++)
    175 		edit_head_field(d, f, modify);
    176 }
    177 
    178 void
    179 edit_geo(struct disklabel *d)
    180 {
    181 	int nsect, ntrack, ncyl, spc;
    182 
    183 	nsect = ntrack = ncyl = spc = 0;
    184 
    185 	printf("Sectors/track: ");
    186 	fflush(stdout);
    187 	if (fgets(tmpbuf, sizeof(tmpbuf), stdin) == NULL)
    188 		return;
    189 	if (sscanf(tmpbuf, "%d", &nsect) != 1)
    190 		nsect = d->d_nsectors;
    191 	printf("Track/cyl: ");
    192 	fflush(stdout);
    193 	if (fgets(tmpbuf, sizeof(tmpbuf), stdin) == NULL)
    194 		return;
    195 	if (sscanf(tmpbuf, "%d", &ntrack) != 1)
    196 		ntrack = d->d_ntracks;
    197 	if (!nsect || !ntrack)
    198 		return;
    199 	spc = nsect * ntrack;
    200 	if (!(ncyl = d->d_secperunit / spc))
    201 		return;
    202 	d->d_nsectors   = nsect;
    203 	d->d_ntracks    = ntrack;
    204 	d->d_ncylinders = ncyl;
    205 	d->d_secpercyl  = spc;
    206 }
    207 
    208 void
    209 print_val_cts(struct disklabel *d, u_long val)
    210 {
    211 	int	sects, trks, cyls;
    212 	char	marker;
    213 	char	buf[80];
    214 
    215 	marker = (val % d->d_secpercyl) ? '*' : ' ';
    216 	sects  = val % d->d_nsectors;
    217 	cyls   = val / d->d_nsectors;
    218 	trks   = cyls % d->d_ntracks;
    219 	cyls  /= d->d_ntracks;
    220 	snprintf(buf, sizeof(buf), "(%d/%02d/%02d)%c", cyls, trks, sects,
    221 	    marker);
    222 	printf(" %9ld %16s", val, buf);
    223 }
    224 
    225 void
    226 get_val_cts(struct disklabel *d, char *buf, u_int32_t *result)
    227 {
    228 	u_long tmp;
    229 	int	cyls, trks, sects;
    230 
    231 	tmp = sscanf(buf, "%d/%d/%d", &cyls, &trks, &sects);
    232 	if (tmp == 1)
    233 		*result = cyls;	/* really nblks! */
    234 	if (tmp == 3) {
    235 		tmp = cyls;
    236 		tmp *= d->d_ntracks;
    237 		tmp += trks;
    238 		tmp *= d->d_nsectors;
    239 		tmp += sects;
    240 		*result = tmp;
    241 	}
    242 }
    243 
    244 void
    245 get_fstype(char *buf, u_int8_t *fstype)
    246 {
    247 	int	i, len;
    248 
    249 	/* An empty response retains previous value */
    250 	if (buf[0] == '\n')
    251 		return;
    252 	for (i = 0, len = strlen(buf) - 1; i < FSMAXTYPES; i++) {
    253 		if (!strncasecmp(buf, fstypenames[i], len)) {
    254 			*fstype = i;
    255 			return;
    256 		}
    257 	}
    258 }
    259 
    260 void
    261 edit_partition(struct disklabel *d, int idx, int modify)
    262 {
    263 	struct partition *p;
    264 	char letter;
    265 	const char *comment;
    266 
    267 	if ((idx < 0) || (idx >= maxpartitions)) {
    268 		printf("bad partition index\n");
    269 		return;
    270 	}
    271 
    272 	p = &d->d_partitions[idx];
    273 	letter = 'a' + idx;
    274 
    275 	/* Set hint about partition type */
    276 	if (idx == rawpartition)
    277 		comment = "disk";
    278 	else {
    279 		comment = "user";
    280 		switch(idx) {
    281 			case 0:
    282 				comment = "root";
    283 			break;
    284 			case 1:
    285 				comment = "swap";
    286 				break;
    287 		}
    288 	}
    289 
    290 	/* Print current value... */
    291 	printf(" %c (%s) ", letter, comment);
    292 	print_val_cts(d, p->p_offset);
    293 	print_val_cts(d, p->p_size);
    294 	printf(" %s\n", fstypenames[p->p_fstype]);
    295 
    296 	if (modify == 0)
    297 		return;
    298 
    299 	/* starting block, or cyls/trks/sects */
    300 	printf("start as <blkno> or <cyls/trks/sects> : ");
    301 	fflush(stdout);
    302 	if (fgets(tmpbuf, sizeof(tmpbuf), stdin) == NULL)
    303 		return;
    304 	get_val_cts(d, tmpbuf, &p->p_offset);
    305 
    306 	/* number of blocks, or cyls/trks/sects */
    307 	printf("length as <nblks> or <cyls/trks/sects> : ");
    308 	fflush(stdout);
    309 	if (fgets(tmpbuf, sizeof(tmpbuf), stdin) == NULL)
    310 		return;
    311 	get_val_cts(d, tmpbuf, &p->p_size);
    312 	/* partition type */
    313 	printf("type: ");
    314 	fflush(stdout);
    315 	if (fgets(tmpbuf, sizeof(tmpbuf), stdin) == NULL)
    316 		return;
    317 	get_fstype(tmpbuf, &p->p_fstype);
    318 }
    319 
    320 /*****************************************************************/
    321 
    322 void
    323 check_divisors(struct disklabel *d)
    324 {
    325 	if (d->d_nsectors == 0) {
    326 		d->d_nsectors = 1;
    327 		printf("bad sect/trk, set to 1\n");
    328 	}
    329 	if (d->d_ntracks == 0) {
    330 		d->d_ntracks = 1;
    331 		printf("bad trks/cyl, set to 1\n");
    332 	}
    333 	if (d->d_ncylinders == 0) {
    334 		d->d_ncylinders = 1;
    335 		printf("bad cyls, set to 1\n");
    336 	}
    337 	if (d->d_secpercyl == 0) {
    338 		d->d_secpercyl = (d->d_nsectors * d->d_ntracks);
    339 		printf("bad sect/cyl, set to %d\n", d->d_secpercyl);
    340 	}
    341 
    342 }
    343 
    344 u_short
    345 dkcksum(struct disklabel *d)
    346 {
    347 	u_short *start, *end;
    348 	u_short sum = 0;
    349 
    350 	start = (u_short *)d;
    351 	end = (u_short *)&d->d_partitions[d->d_npartitions];
    352 	while (start < end)
    353 		sum ^= *start++;
    354 	return (sum);
    355 }
    356 
    357 void
    358 label_write(struct disklabel *d, char *dn)
    359 {
    360 	int fd;
    361 
    362 	d->d_magic = DISKMAGIC;
    363 	d->d_magic2 = DISKMAGIC;
    364 	d->d_checksum = 0;
    365 	d->d_checksum = dkcksum(d);
    366 
    367 	fd = open(dn, O_RDWR, 0);
    368 	if (fd < 0) {
    369 		perror(dn);
    370 		return;
    371 	}
    372 	if (ioctl(fd, DIOCWDINFO, d) < 0) {
    373 		perror("ioctl DIOCWDINFO");
    374 	}
    375 	close(fd);
    376 }
    377 
    378 void
    379 label_read(struct disklabel *dl, char *dn)
    380 {
    381 	int fd;
    382 
    383 	fd = open(dn, O_RDONLY, 0);
    384 	if (fd < 0) {
    385 		perror(dn);
    386 		exit(1);
    387 	}
    388 	if (ioctl(fd, DIOCGDINFO, dl) < 0) {
    389 		if (errno == ESRCH)
    390 			fprintf(stderr, "edlabel: No disk label on disk\n");
    391 		else
    392 		    	perror("ioctl DIOCGDINFO");
    393 		exit(1);
    394 	}
    395 
    396 	/* Make sure divisors are non-zero. */
    397 	check_divisors(dl);
    398 
    399 	close(fd);
    400 }
    401 
    402 /*****************************************************************/
    403 
    404 void
    405 label_print(struct disklabel *dl, char *dn)
    406 {
    407 	int i;
    408 
    409 	/* Print out head stuff. */
    410 	edit_head_all(dl, 0);
    411 
    412 	/* And the partition header. */
    413 	printf("partition%6sstart%9s(c/t/s)%6snblks%9s(c/t/s)  type\n\n"
    414 							"", "", "", "", "");
    415 	for (i = 0; i < dl->d_npartitions; i++)
    416 		edit_partition(dl, i, 0);
    417 }
    418 
    419 char modify_cmds[] = "modify subcommands:\n\
    420  @   : modify disk parameters\n\
    421  a-%c : modify partition\n%s\
    422  q   : quit this subcommand\n";
    423 
    424 void
    425 label_modify(struct disklabel *dl, char *dn)
    426 {
    427 	int c, i;
    428 	int scsi_fict = 0;
    429 
    430 	if (!strcmp(dl->d_typename, "SCSI disk")
    431 	     && !strcmp(dl->d_packname, "fictitious"))
    432 		scsi_fict = 1;
    433 
    434 	printf(modify_cmds, 'a' + maxpartitions - 1,
    435 		scsi_fict ? " s   : standardize geometry\n" : "");
    436 	for (;;) {
    437 		printf("edlabel/modify> ");
    438 		fflush(stdout);
    439 		if (fgets(tmpbuf, sizeof(tmpbuf), stdin) == NULL)
    440 			break;
    441 		c = tmpbuf[0];
    442 		if ((c == '\0') || (c == '\n'))
    443 			continue;	/* blank line */
    444 		if (c == 'q')
    445 			break;
    446 		if (c == '@') {
    447 			edit_head_all(dl, 1);
    448 			check_divisors(dl);
    449 			continue;
    450 		}
    451 		if ((c == 's') && scsi_fict) {
    452 			edit_geo(dl);
    453 			continue;
    454 		}
    455 		if ((c < 'a') || (c > 'q')) {
    456 			printf("bad input.  ");
    457 			printf(modify_cmds, 'a' + maxpartitions - 1,
    458 			    scsi_fict ? " s   : standardize geometry\n" : "");
    459 			continue;
    460 		}
    461 		edit_partition(dl, c - 'a', 1);
    462 	}
    463 	/* Set the d_npartitions field correctly */
    464 	for (i = 0; i < maxpartitions; i++) {
    465 		if (dl->d_partitions[i].p_size)
    466 			dl->d_npartitions = i + 1;
    467 	}
    468 
    469 }
    470 
    471 void
    472 label_quit(struct disklabel *dl, char *dn)
    473 {
    474 	exit(0);
    475 }
    476 
    477 struct cmd {
    478 	void (*cmd_func)(struct disklabel *, char *);
    479 	const char *cmd_name;
    480 	const char *cmd_descr;
    481 } cmds[] = {
    482 	{ label_print,  "print",  "display the current disk label" },
    483 	{ label_modify, "modify", "prompt for changes to the label" },
    484 	{ label_write,  "write",  "write the new label to disk" },
    485 	{ label_quit,   "quit",   "terminate program" },
    486 	{ .cmd_func = 0 },
    487 };
    488 
    489 void
    490 menu(void)
    491 {
    492 	struct cmd *cmd;
    493 
    494 	printf("edlabel menu:\n");
    495 	for (cmd = cmds; cmd->cmd_func; cmd++)
    496 		printf("%s\t- %s\n", cmd->cmd_name, cmd->cmd_descr);
    497 }
    498 
    499 int
    500 main(int argc, char **argv)
    501 {
    502 	struct disklabel dl;
    503 	struct cmd *cmd;
    504 	char *dev_name;
    505 
    506 	if (argc != 2) {
    507 		fprintf(stderr, "usage: edlabel RAWDISK\n");
    508 		exit(1);
    509 	}
    510 	dev_name = argv[1];
    511 
    512 	rawpartition = getrawpartition();
    513 	maxpartitions = getmaxpartitions();
    514 
    515 	label_read(&dl, dev_name);
    516 
    517 	menu();
    518 
    519 	for (;;) {
    520 		printf("edlabel> ");
    521 		fflush(stdout);
    522 		if (fgets(tmpbuf, sizeof(tmpbuf), stdin) == NULL)
    523 			break;
    524 		for (cmd = cmds; cmd->cmd_func; cmd++)
    525 			if (cmd->cmd_name[0] == tmpbuf[0])
    526 				goto found;
    527 		printf("Invalid command.  ");
    528 		menu();
    529 		continue;
    530 
    531 	found:
    532 		cmd->cmd_func(&dl, dev_name);
    533 	}
    534 	exit(0);
    535 }
    536