1 /* $NetBSD: edahdi.c,v 1.8 2009/03/14 21:04:07 dsl Exp $ */
4 * Copyright (c) 1996 Leo Weppelman, Waldi Ravens.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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>
44 #include <sys/disklabel.h>
46 #include <machine/ahdilabel.h>
59 * Internal partition tables:
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 */
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 *);
110 void get_termcap(void);
112 int show_parts(ptable_t
*, int);
113 void update_disk(ptable_t
*, int, int);
116 main(int argc
, char *argv
[])
124 char *prog
= strrchr(argv
[0], '/');
129 fprintf(stderr
, "Usage: %s <raw_disk_device>", prog
);
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");
142 warnx("Disk has no ahdi partitions");
151 if ((ahdi_getparts(fd
, &ptable
, AHDI_BBLOCK
, AHDI_BBLOCK
) != 0)
152 || (ptable
.nparts
== 0))
155 edit_parts(fd
, &ptable
);
160 edit_parts(int fd
, ptable_t
*ptable
)
164 char *error
, *new_id
;
168 tputs(Clr_screen
, 1, putchar
);
169 show_parts(ptable
, scr_base
);
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? ");
180 switch (lex(&value
)) {
185 error
= "Invalid command";
188 for (value
= 0; value
< ptable
->nparts
; value
++) {
189 if (ptable
->parts
[value
].mod
) {
190 printf("\nThere are unwritten changes."
191 " Quit anyway? [n] ");
193 if ((value
== 'y') || (value
== 'Y'))
195 while (value
!= '\n')
200 if (value
== ptable
->nparts
)
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
);
213 if ((scr_base
+ MAX_PSHOWN
) < ptable
->nparts
)
214 scr_base
+= MAX_PSHOWN
;
217 scr_base
-= MAX_PSHOWN
;
222 if (value
>= ptable
->nparts
) {
223 error
= "Not that many partitions";
226 if ((new_id
= get_id()) == NULL
) {
227 error
= "Invalid id";
230 strncpy(ptable
->parts
[value
].id
, new_id
, 3);
231 ptable
->parts
[value
].mod
= 1;
232 scr_base
= (value
/ MAX_PSHOWN
) * MAX_PSHOWN
;
235 error
= "Internal error - unknown token";
239 printf("\n\n%s", error
);
247 show_parts(ptable_t
*ptable
, int nr
)
253 if (nr
>= ptable
->nparts
)
254 return (0); /* Nothing to show */
256 printf("nr root desc id start end MBs\n");
258 p
= &ptable
->parts
[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
,
264 p
->rsec
, p
->rent
, p
->id
, p
->start
, p
->end
, megs
);
279 if ((nch
= read (0, c
, 1)) != 1) {
298 if (isspace((unsigned char)*c
)) {
303 else if (isdigit((unsigned char)*c
)) {
304 *value
= (10 * *value
) + *c
- '0';
313 * Flush rest of line before returning
315 while (read (0, c
, 1) == 1)
316 if ((*c
== '\n') || (*c
== '\r'))
326 printf("\nEnter new id: ");
327 if (fgets(buf
, sizeof(buf
), stdin
) == NULL
)
329 for (n
= 0; n
< 3; n
++) {
330 if (!isalpha((unsigned char)buf
[n
]))
332 buf
[n
] = toupper((unsigned char)buf
[n
]);
339 bsd_label(int fd
, u_int offset
)
345 nsec
= (BBMINSIZE
+ (DEV_BSIZE
- 1)) / DEV_BSIZE
;
346 bblk
= disk_read(fd
, offset
, nsec
);
350 end
= (u_int
*)&bblk
[BBMINSIZE
- sizeof(struct disklabel
)];
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
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
];
387 ahdi_cksum(void *buf
)
389 unsigned short *p
= (unsigned short *)buf
;
390 unsigned short csum
= 0;
394 for(i
= 0; i
< 256; i
++)
396 *--p
= (0x1234 - csum
) & 0xffff;
401 ahdi_getparts(fd
, ptable
, rsec
, esec
)
407 struct ahdi_part
*part
, *end
;
408 struct ahdi_root
*root
;
411 root
= disk_read(fd
, rsec
, 1);
413 rv
= rsec
+ (rsec
== 0);
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))
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
);
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");
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;
445 p
->rent
= part
- root
->ar_parts
;
456 disk_read(fd
, start
, count
)
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
) {
472 err(1, "Seek error");
474 if (read(fd
, buffer
, size
) != size
) {
476 err(1, "Read error");
483 update_disk(ptable_t
*ptable
, int fd
, int pno
)
485 struct ahdi_root
*root
;
486 struct ahdi_part
*apart
;
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
];
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];
513 disk_write(fd
, rsec
, 1, root
);
518 disk_write(fd
, start
, count
, buf
)
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");
539 char *term
, tbuf
[1024], buf
[1024], *p
;
541 if ((term
= getenv("TERM")) == NULL
)
542 warnx("No TERM environment variable!");
544 if (tgetent(tbuf
, term
) != 1)
545 errx(1, "Tgetent failure.");
547 if (tgetstr("cl", &p
)) {
548 if ((Clr_screen
= malloc(strlen(buf
) + 1)) == NULL
)
549 errx(1, "Malloc failure.");
550 strcpy(Clr_screen
, buf
);