Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / atari / stand / edahdi / edahdi.c
blob484733375a8a2c4c2efd67d5092a32f5739817ee
1 /* $NetBSD: edahdi.c,v 1.8 2009/03/14 21:04:07 dsl Exp $ */
3 /*
4 * Copyright (c) 1996 Leo Weppelman, Waldi Ravens.
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.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by
18 * Leo Weppelman and Waldi Ravens.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 * This code implements a simple editor for partition id's on disks containing
36 * AHDI partition info.
38 * Credits for the code handling disklabels goes to Waldi Ravens.
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/stat.h>
44 #include <sys/disklabel.h>
46 #include <machine/ahdilabel.h>
48 #include <fcntl.h>
49 #include <stdlib.h>
50 #include <curses.h>
51 #include <termios.h>
52 #include <unistd.h>
53 #include <stdio.h>
54 #include <string.h>
55 #include <err.h>
56 #include <ctype.h>
59 * Internal partition tables:
61 typedef struct {
62 char id[4];
63 u_int start;
64 u_int end;
65 u_int rsec;
66 u_int rent;
67 int mod;
68 } part_t;
70 typedef struct {
71 int nparts;
72 part_t *parts;
73 } ptable_t;
76 * I think we can savely assume a fixed blocksize - AHDI won't support
77 * something different...
79 #define BLPM ((1024 * 1024) / DEV_BSIZE)
82 * #Partition entries shown on the screen at once
84 #define MAX_PSHOWN 16 /* #partitions shown on screen */
87 * Tokens:
89 #define T_INVAL 0
90 #define T_QUIT 1
91 #define T_WRITE 2
92 #define T_NEXT 3
93 #define T_PREV 4
94 #define T_NUMBER 5
95 #define T_EOF 6
98 * Terminal capability strings (Ok, 1 to start with ;-) )
100 char *Clr_screen = "";
102 void ahdi_cksum(void *);
103 u_int ahdi_getparts(int, ptable_t *, u_int, u_int);
104 int bsd_label(int, u_int);
105 int dkcksum(struct disklabel *);
106 int edit_parts(int, ptable_t *);
107 void *disk_read(int, u_int, u_int);
108 void disk_write(int, u_int, u_int, void *);
109 char *get_id(void);
110 void get_termcap(void);
111 int lex(int *);
112 int show_parts(ptable_t *, int);
113 void update_disk(ptable_t *, int, int);
116 main(int argc, char *argv[])
118 int fd;
119 ptable_t ptable;
120 int rv;
121 struct stat st;
123 if (argc != 2) {
124 char *prog = strrchr(argv[0], '/');
126 if (prog == NULL)
127 prog = argv[0];
128 else prog++;
129 fprintf(stderr, "Usage: %s <raw_disk_device>", prog);
130 exit(1);
132 if ((fd = open(argv[1], O_RDWR)) < 0)
133 err(1, "Cannot open '%s'.", argv[1]);
134 if (fstat(fd, &st) < 0)
135 err(1, "Cannot stat '%s'.", argv[1]);
136 if (!S_ISCHR(st.st_mode))
137 errx(1, "'%s' must be a character special device.", argv[1]);
139 if ((rv = bsd_label(fd, LABELSECTOR)) < 0)
140 errx(1, "I/O error");
141 if (rv == 0) {
142 warnx("Disk has no ahdi partitions");
143 return (2);
146 get_termcap();
148 ptable.nparts = 0;
149 ptable.parts = NULL;
151 if ((ahdi_getparts(fd, &ptable, AHDI_BBLOCK, AHDI_BBLOCK) != 0)
152 || (ptable.nparts == 0))
153 exit (1);
155 edit_parts(fd, &ptable);
156 return (0);
160 edit_parts(int fd, ptable_t *ptable)
162 int scr_base = 0;
163 int value;
164 char *error, *new_id;
166 for (;;) {
167 error = NULL;
168 tputs(Clr_screen, 1, putchar);
169 show_parts(ptable, scr_base);
171 printf("\n\n");
172 printf("q : quit - don't update the disk\n");
173 printf("w : write changes to disk\n");
174 printf("> : next screen of partitions\n");
175 printf("< : previous screen of partitions\n");
176 printf("<nr> : modify id of partition <nr>\n");
177 printf("\n\nCommand? ");
178 fflush(stdout);
180 switch (lex(&value)) {
181 case T_EOF:
182 exit(0);
184 case T_INVAL:
185 error = "Invalid command";
186 break;
187 case T_QUIT :
188 for (value = 0; value < ptable->nparts; value++) {
189 if (ptable->parts[value].mod) {
190 printf("\nThere are unwritten changes."
191 " Quit anyway? [n] ");
192 value = getchar();
193 if ((value == 'y') || (value == 'Y'))
194 exit (0);
195 while (value != '\n')
196 value = getchar();
197 break;
200 if (value == ptable->nparts)
201 exit(0);
202 break;
203 case T_WRITE:
204 error = "No changes to write";
205 for (value = 0; value < ptable->nparts; value++) {
206 if (ptable->parts[value].mod) {
207 update_disk(ptable, fd, value);
208 error = "";
211 break;
212 case T_NEXT :
213 if ((scr_base + MAX_PSHOWN) < ptable->nparts)
214 scr_base += MAX_PSHOWN;
215 break;
216 case T_PREV :
217 scr_base -= MAX_PSHOWN;
218 if (scr_base < 0)
219 scr_base = 0;
220 break;
221 case T_NUMBER:
222 if (value >= ptable->nparts) {
223 error = "Not that many partitions";
224 break;
226 if ((new_id = get_id()) == NULL) {
227 error = "Invalid id";
228 break;
230 strncpy(ptable->parts[value].id, new_id, 3);
231 ptable->parts[value].mod = 1;
232 scr_base = (value / MAX_PSHOWN) * MAX_PSHOWN;
233 break;
234 default :
235 error = "Internal error - unknown token";
236 break;
238 if (error != NULL) {
239 printf("\n\n%s", error);
240 fflush(stdout);
241 sleep(2);
247 show_parts(ptable_t *ptable, int nr)
249 int i;
250 part_t *p;
251 u_int megs;
253 if (nr >= ptable->nparts)
254 return (0); /* Nothing to show */
255 printf("\n\n");
256 printf("nr root desc id start end MBs\n");
258 p = &ptable->parts[nr];
259 i = nr;
260 for(; (i < ptable->nparts) && ((i - nr) < MAX_PSHOWN); i++, p++) {
261 megs = ((p->end - p->start + 1) + (BLPM >> 1)) / BLPM;
262 printf("%2d%s %8u %4u %s %8u %8u (%3u)\n", i,
263 p->mod ? "*" : " ",
264 p->rsec, p->rent, p->id, p->start, p->end, megs);
266 return (1);
270 lex(int *value)
272 char c[1];
273 int rv, nch;
275 rv = T_INVAL;
277 *value = 0;
278 for (;;) {
279 if ((nch = read (0, c, 1)) != 1) {
280 if (nch == 0)
281 return (T_EOF);
282 else return (rv);
284 switch (*c) {
285 case 'q':
286 rv = T_QUIT;
287 goto out;
288 case 'w':
289 rv = T_WRITE;
290 goto out;
291 case '>':
292 rv = T_NEXT;
293 goto out;
294 case '<':
295 rv = T_PREV;
296 goto out;
297 default :
298 if (isspace((unsigned char)*c)) {
299 if (rv == T_INVAL)
300 break;
301 goto out;
303 else if (isdigit((unsigned char)*c)) {
304 *value = (10 * *value) + *c - '0';
305 rv = T_NUMBER;
307 goto out;
310 /* NOTREACHED */
311 out:
313 * Flush rest of line before returning
315 while (read (0, c, 1) == 1)
316 if ((*c == '\n') || (*c == '\r'))
317 break;
318 return (rv);
321 char *
322 get_id(void)
324 static char buf[5];
325 int n;
326 printf("\nEnter new id: ");
327 if (fgets(buf, sizeof(buf), stdin) == NULL)
328 return (NULL);
329 for (n = 0; n < 3; n++) {
330 if (!isalpha((unsigned char)buf[n]))
331 return (NULL);
332 buf[n] = toupper((unsigned char)buf[n]);
334 buf[3] = '\0';
335 return (buf);
339 bsd_label(int fd, u_int offset)
341 u_char *bblk;
342 u_int nsec;
343 int rv;
345 nsec = (BBMINSIZE + (DEV_BSIZE - 1)) / DEV_BSIZE;
346 bblk = disk_read(fd, offset, nsec);
347 if (bblk) {
348 u_int *end, *p;
350 end = (u_int *)&bblk[BBMINSIZE - sizeof(struct disklabel)];
351 rv = 1;
352 for (p = (u_int *)bblk; p < end; ++p) {
353 struct disklabel *dl = (struct disklabel *)&p[1];
354 if ( ( (p[0] == NBDAMAGIC && offset == 0)
355 || (p[0] == AHDIMAGIC && offset != 0)
356 || (u_char *)dl - bblk == 7168
358 && dl->d_npartitions <= MAXPARTITIONS
359 && dl->d_magic2 == DISKMAGIC
360 && dl->d_magic == DISKMAGIC
361 && dkcksum(dl) == 0
363 rv = 0;
364 break;
367 free(bblk);
369 else rv = -1;
371 return(rv);
375 dkcksum(struct disklabel *dl)
377 u_short *start, *end, sum = 0;
379 start = (u_short *)dl;
380 end = (u_short *)&dl->d_partitions[dl->d_npartitions];
381 while (start < end)
382 sum ^= *start++;
383 return(sum);
386 void
387 ahdi_cksum(void *buf)
389 unsigned short *p = (unsigned short *)buf;
390 unsigned short csum = 0;
391 int i;
393 p[255] = 0;
394 for(i = 0; i < 256; i++)
395 csum += *p++;
396 *--p = (0x1234 - csum) & 0xffff;
400 u_int
401 ahdi_getparts(fd, ptable, rsec, esec)
402 int fd;
403 ptable_t *ptable;
404 u_int rsec,
405 esec;
407 struct ahdi_part *part, *end;
408 struct ahdi_root *root;
409 u_int rv;
411 root = disk_read(fd, rsec, 1);
412 if (!root) {
413 rv = rsec + (rsec == 0);
414 goto done;
417 if (rsec == AHDI_BBLOCK)
418 end = &root->ar_parts[AHDI_MAXRPD];
419 else end = &root->ar_parts[AHDI_MAXARPD];
420 for (part = root->ar_parts; part < end; ++part) {
421 u_int id = *((u_int32_t *)&part->ap_flg);
422 if (!(id & 0x01000000))
423 continue;
424 if ((id &= 0x00ffffff) == AHDI_PID_XGM) {
425 u_int offs = part->ap_st + esec;
426 rv = ahdi_getparts(fd, ptable, offs,
427 esec == AHDI_BBLOCK ? offs : esec);
428 if (rv)
429 goto done;
430 } else {
431 part_t *p;
432 u_int i = ++ptable->nparts;
433 ptable->parts = realloc(ptable->parts,
434 i * sizeof *ptable->parts);
435 if (ptable->parts == NULL) {
436 fprintf(stderr, "Allocation error\n");
437 rv = 1;
438 goto done;
440 p = &ptable->parts[--i];
441 *((u_int32_t *)&p->id) = id << 8;
442 p->start = part->ap_st + rsec;
443 p->end = p->start + part->ap_size - 1;
444 p->rsec = rsec;
445 p->rent = part - root->ar_parts;
446 p->mod = 0;
449 rv = 0;
450 done:
451 free(root);
452 return(rv);
455 void *
456 disk_read(fd, start, count)
457 int fd;
458 u_int start,
459 count;
461 char *buffer;
462 off_t offset;
463 size_t size;
465 size = count * DEV_BSIZE;
466 offset = start * DEV_BSIZE;
467 if ((buffer = malloc(size)) == NULL)
468 errx(1, "No memory");
470 if (lseek(fd, offset, SEEK_SET) != offset) {
471 free(buffer);
472 err(1, "Seek error");
474 if (read(fd, buffer, size) != size) {
475 free(buffer);
476 err(1, "Read error");
477 exit(1);
479 return(buffer);
482 void
483 update_disk(ptable_t *ptable, int fd, int pno)
485 struct ahdi_root *root;
486 struct ahdi_part *apart;
487 part_t *lpart;
488 u_int rsec;
489 int i;
491 rsec = ptable->parts[pno].rsec;
492 root = disk_read(fd, rsec, 1);
495 * Look for additional mods on the same sector
497 for (i = 0; i < ptable->nparts; i++) {
498 lpart = &ptable->parts[i];
499 if (lpart->mod && (lpart->rsec == rsec)) {
500 apart = &root->ar_parts[lpart->rent];
502 /* Paranoia.... */
503 if ((lpart->end - lpart->start + 1) != apart->ap_size)
504 errx(1, "Updating wrong partition!");
505 apart->ap_id[0] = lpart->id[0];
506 apart->ap_id[1] = lpart->id[1];
507 apart->ap_id[2] = lpart->id[2];
508 lpart->mod = 0;
511 if (rsec == 0)
512 ahdi_cksum(root);
513 disk_write(fd, rsec, 1, root);
514 free(root);
517 void
518 disk_write(fd, start, count, buf)
519 int fd;
520 u_int start,
521 count;
522 void *buf;
524 off_t offset;
525 size_t size;
527 size = count * DEV_BSIZE;
528 offset = start * DEV_BSIZE;
530 if (lseek(fd, offset, SEEK_SET) != offset)
531 err(1, "Seek error");
532 if (write(fd, buf, size) != size)
533 err(1, "Write error");
536 void
537 get_termcap(void)
539 char *term, tbuf[1024], buf[1024], *p;
541 if ((term = getenv("TERM")) == NULL)
542 warnx("No TERM environment variable!");
543 else {
544 if (tgetent(tbuf, term) != 1)
545 errx(1, "Tgetent failure.");
546 p = buf;
547 if (tgetstr("cl", &p)) {
548 if ((Clr_screen = malloc(strlen(buf) + 1)) == NULL)
549 errx(1, "Malloc failure.");
550 strcpy(Clr_screen, buf);