No empty .Rs/.Re
[netbsd-mini2440.git] / sbin / edlabel / edlabel.c
blobf5b5a00c9e4d884f36a8b5b76a5a0f5ac3786eac
1 /* $NetBSD: edlabel.c,v 1.16 2006/10/23 03:56:38 mrg Exp $ */
3 /*
4 * Copyright (c) 1995 Gordon W. Ross
5 * All rights reserved.
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.
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.
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>
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>
45 * Machine dependent constants you want to retrieve only once...
47 int rawpartition, maxpartitions;
50 * This is a data-driven program
52 struct field {
53 const char *f_name;
54 int f_offset;
55 int f_type; /* 1:char, 2:short, 4:int, >4:string */
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 },
73 #undef dloff
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);
91 char tmpbuf[64];
93 void
94 edit_head_field(void *v, struct field *f, int modify /* also modify */)
96 u_int8_t *cp;
97 u_int tmp;
99 cp = v;
100 cp += f->f_offset;
102 printf("%s: ", f->f_name);
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;
119 default:
120 /* must be a string. */
121 strlcpy(tmpbuf, (char*)cp, sizeof(tmpbuf));
122 printf("%s", tmpbuf);
123 break;
126 if (modify == 0) {
127 printf("\n");
128 return;
130 printf(" ? ");
131 fflush(stdout);
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;
141 /* store new value */
142 if (f->f_type <= 4)
143 if (sscanf(tmpbuf, "%d", &tmp) != 1)
144 return;
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;
168 void
169 edit_head_all(struct disklabel *d, int modify)
171 struct field *f;
173 /* Edit head stuff. */
174 for (f = label_head; f->f_name; f++)
175 edit_head_field(d, f, modify);
178 void
179 edit_geo(struct disklabel *d)
181 int nsect, ntrack, ncyl, spc;
183 nsect = ntrack = ncyl = spc = 0;
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;
208 void
209 print_val_cts(struct disklabel *d, u_long val)
211 int sects, trks, cyls;
212 char marker;
213 char buf[80];
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);
225 void
226 get_val_cts(struct disklabel *d, char *buf, u_int32_t *result)
228 u_long tmp;
229 int cyls, trks, sects;
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;
244 void
245 get_fstype(char *buf, u_int8_t *fstype)
247 int i, len;
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;
260 void
261 edit_partition(struct disklabel *d, int idx, int modify)
263 struct partition *p;
264 char letter;
265 const char *comment;
267 if ((idx < 0) || (idx >= maxpartitions)) {
268 printf("bad partition index\n");
269 return;
272 p = &d->d_partitions[idx];
273 letter = 'a' + idx;
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;
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]);
296 if (modify == 0)
297 return;
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);
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);
320 /*****************************************************************/
322 void
323 check_divisors(struct disklabel *d)
325 if (d->d_nsectors == 0) {
326 d->d_nsectors = 1;
327 printf("bad sect/trk, set to 1\n");
329 if (d->d_ntracks == 0) {
330 d->d_ntracks = 1;
331 printf("bad trks/cyl, set to 1\n");
333 if (d->d_ncylinders == 0) {
334 d->d_ncylinders = 1;
335 printf("bad cyls, set to 1\n");
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);
344 u_short
345 dkcksum(struct disklabel *d)
347 u_short *start, *end;
348 u_short sum = 0;
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);
357 void
358 label_write(struct disklabel *d, char *dn)
360 int fd;
362 d->d_magic = DISKMAGIC;
363 d->d_magic2 = DISKMAGIC;
364 d->d_checksum = 0;
365 d->d_checksum = dkcksum(d);
367 fd = open(dn, O_RDWR, 0);
368 if (fd < 0) {
369 perror(dn);
370 return;
372 if (ioctl(fd, DIOCWDINFO, d) < 0) {
373 perror("ioctl DIOCWDINFO");
375 close(fd);
378 void
379 label_read(struct disklabel *dl, char *dn)
381 int fd;
383 fd = open(dn, O_RDONLY, 0);
384 if (fd < 0) {
385 perror(dn);
386 exit(1);
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);
396 /* Make sure divisors are non-zero. */
397 check_divisors(dl);
399 close(fd);
402 /*****************************************************************/
404 void
405 label_print(struct disklabel *dl, char *dn)
407 int i;
409 /* Print out head stuff. */
410 edit_head_all(dl, 0);
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);
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";
424 void
425 label_modify(struct disklabel *dl, char *dn)
427 int c, i;
428 int scsi_fict = 0;
430 if (!strcmp(dl->d_typename, "SCSI disk")
431 && !strcmp(dl->d_packname, "fictitious"))
432 scsi_fict = 1;
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;
451 if ((c == 's') && scsi_fict) {
452 edit_geo(dl);
453 continue;
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;
461 edit_partition(dl, c - 'a', 1);
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;
471 void
472 label_quit(struct disklabel *dl, char *dn)
474 exit(0);
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 },
489 void
490 menu(void)
492 struct cmd *cmd;
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);
500 main(int argc, char **argv)
502 struct disklabel dl;
503 struct cmd *cmd;
504 char *dev_name;
506 if (argc != 2) {
507 fprintf(stderr, "usage: edlabel RAWDISK\n");
508 exit(1);
510 dev_name = argv[1];
512 rawpartition = getrawpartition();
513 maxpartitions = getmaxpartitions();
515 label_read(&dl, dev_name);
517 menu();
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;
531 found:
532 cmd->cmd_func(&dl, dev_name);
534 exit(0);