Add externs to avoid multiple definitions, and then add missing definitions.
[rrq/maintain_lilo.git] / diagnose / test5.c
1 /* test5.c */
2 /*
3  Copyright (C) 2004 John Coffman.
4  All rights reserved.
5
6  Licensed under the terms contained in the file 'COPYING' in the LILO
7  source directory.
8
9 */
10 #include <bios.h>
11 #include <time.h>
12 #include "../src/bdata.h"
13
14 #define DISK_VERSION "3.0"
15
16 #if __MSDOS__==0
17 #define putch bios_putc
18 #define getch bios_getc
19 #define printf cprintf
20 #define CR 13
21 #else
22 #include <stdio.h>
23 #define putch(c) fputc((c),stdout)
24 #define getch getchar
25 #define CR 10
26 #endif
27
28 #define CTRL_C 03
29 #define SPACER "\f\n"
30
31
32 #ifndef EDD_SUBSET
33 #define EDD_SUBSET 4
34 #define EDD_LOCK 2
35 #define EDD_PACKET 1
36 #endif
37 #ifndef SECTOR_SIZE
38 #define SECTOR_SIZE 512
39 #endif
40
41 #define CL_MAGIC_ADDR 0x20
42 #define CL_MAGIC 0xa33f
43 #define CL_OFFSET 0x22
44 #define CL_LENGTH 256
45
46 typedef unsigned char  byte;
47 typedef unsigned short word;
48 typedef unsigned long dword;
49
50 extern union REGS   __argr;
51 extern struct SREGS __argseg;
52
53 union REGS reg, oreg;
54 struct SREGS sreg;
55
56 int num_hd = BD_MAX_HARD;
57 int errno;
58 enum {RD=0, WR=1};
59
60 struct Buffer {
61     int dirty, device;
62     union {
63         byte sector[SECTOR_SIZE];
64         word wsector[SECTOR_SIZE/2];
65         dword dsector[SECTOR_SIZE/4];
66     } x;
67 } buffer;
68
69 unsigned long linear(void *ptr)
70 {
71     segread(&sreg);
72     return ((unsigned long)sreg.ds<<4) + (unsigned int)ptr;
73 }
74
75
76 #if __MSDOS__==0
77 static
78 bios_putc0(int c)
79 {
80     union REGS reg;
81     if (c=='\f') {
82         reg.h.ah = 0x0F;
83         int86(0x10, &reg, &reg);
84         reg.h.ah = 0;
85         int86(0x10, &reg, &reg);
86     } else {
87         reg.h.al = c;
88         reg.h.ah = 14;
89         reg.x.bx = 7;
90         int86(0x10, &reg, &reg);
91     }
92 }
93
94 void bios_putc(char c)
95 {
96 static int col;
97    
98     switch(c) {
99     case '\t':
100         do bios_putc(' '); while(col&7);
101         break;
102     case '\n':  bios_putc0('\r');
103         /* fall into CR */
104     case '\f':
105     case '\r':  col=0;
106     default:
107         bios_putc0(c);
108         if (c>=' ' && c<0177) col++;
109     }
110 }
111 #endif
112
113 static
114 void sizeit(unsigned long sectors)
115 {
116 static char suf[] = "KMGT";
117     int fract;
118     char *cp;
119
120 /* print disk size in K,M,G,T */
121     sectors /= 2;
122     cp = suf;
123     if (sectors <= 999) {
124         printf("%ld%c", sectors, *cp);
125         return;
126     }
127     cp++;
128     while (sectors > 999999) {
129         sectors /= 1000;
130         cp++;
131     }
132     if (sectors > 2999) {
133         sectors *= 1024;
134         sectors /= 1000;
135     }
136     sectors += 5;       /* round decimal part */
137     sectors /= 10;
138     fract = sectors % 100;
139     sectors /= 100;
140     printf("%ld.%02d%c", sectors, fract, *cp);
141 }
142
143 static
144 void banner(char *version)
145 {
146         printf( "\n\n\n"
147 ">>>> Disk Maintenance Tools <<<<\n\n\n"
148 "Version %s, Copyright (C) 2004  John Coffman <johninsd@san.rr.com>\n"
149 "Portions Copyright (C) 1996-2001 Robert de Bath, used with permission\n"
150 "Re-use and redistribution rights set forth in the file \"COPYING\".\n\n",
151          version);
152 }
153
154
155
156 static
157 int inb(int port)
158 {
159 #asm
160   mov   bx,sp
161   mov   dx,[bx+2]
162   in    al,dx
163   xor   ah,ah
164 #endasm
165 }
166
167 static
168 int outb(int port, int data)
169 {
170 #asm
171   mov   bx,sp
172   mov   dx,[bx+2]
173   mov   ax,[bx+4]
174   out   dx,al
175 #endasm
176 }
177
178 static
179 void yesno(int i)
180 {
181     printf("%s\n", i?"yes":"no");
182 }
183
184 static
185 void decimal(unsigned long value)
186 {
187     unsigned int v[4];
188     int i;
189     for (i=0; i<4; i++) {
190         v[i] = value % 1000;
191         value /= 1000;
192     }
193     if (v[3]) printf("%d,%03d,%03d,%03d", v[3], v[2], v[1], v[0]);
194     else if (v[2]) printf("%d,%03d,%03d", v[2], v[1], v[0]);
195     else if (v[1]) printf("%d,%03d", v[1], v[0]);
196     else printf("%d", v[0]);
197 }
198
199 static
200 void print_regs(union REGS *reg) {
201     printf("AX=%04x  BX=%04x  CX=%04x  DX=%04x  SI=%04x  DI=%04x\n",
202     reg->x.ax, reg->x.bx, reg->x.cx, reg->x.dx, reg->x.si, reg->x.di);
203 }
204
205 static 
206 void print_sregs(struct SREGS *sreg) {
207     printf("DS=%04x  ES=%04x  CS=%04x  SS=%04x\n",
208                 sreg->ds, sreg->es, sreg->cs, sreg->ss);
209 }
210
211 static
212 int is_msdos(void)
213 {
214 #if __MSDOS__
215     return 1;
216 #else
217     return (__argseg.es+0x10 == __argseg.cs);
218 #endif
219 }
220
221 static
222 void pause(void)
223 {
224         char ch;
225 /* Must be standalone */    
226         printf("\n\n\nHit <Enter> to continue, <^C> to quit ...");
227         do {
228             ch = getch();
229             if (ch==CTRL_C) exit(0);
230 #if DEBUG>=1
231             if (ch != CR) printf(" %o", ch);
232 #endif
233         } while (ch != CR);
234         printf("\n");
235 }
236
237 static
238 void video_fix(void)
239 {
240 /* dirty hack for DELL Dimension 4300 computers */
241    printf("\f\n");
242 }
243
244
245 static
246 void setup(int rval)
247 {
248     segread(&sreg);
249     sreg.es = sreg.ds;          /* as a general rule */
250     memset(&reg,rval,sizeof(reg));
251     memset(&oreg,rval,sizeof(oreg));
252 }
253
254
255
256
257 static
258 int peekw_es(int addr)
259 {
260     union {
261         char ch[2];
262         int  w;
263         } tem;
264     tem.ch[0] = __peek_es(addr);
265     tem.ch[1] = __peek_es(addr+1);
266     return tem.w;
267 }
268
269
270 static void get_cmdline(char *cp)
271 {
272     word addr;
273     int ch;
274     
275     __set_es(__argseg.ds);
276     if (peekw_es(CL_MAGIC_ADDR) == CL_MAGIC) {
277         addr = peekw_es(CL_OFFSET);
278         do {
279             ch = __peek_es(addr++);
280         } while (ch && ch != '=');
281         do {
282             *cp++ = ch = __peek_es(addr++);
283         } while (ch);
284     }
285     else *cp = 0;
286 }
287
288 static
289 int num_hard_disks(void)
290 {
291     setup(0);
292     reg.h.ah = 8;
293     reg.h.dl = 0x80;
294     int86(0x13, &reg, &oreg);
295     return oreg.x.cflag ? 0 : (int)oreg.h.dl;
296 }
297
298 static
299 int disk_rw0(int bios, int rw, void *buffer)
300 {
301     int err = 1;
302     int errcnt = 5;
303     int code;
304     while (err && errcnt) {
305         setup(0);
306         reg.h.ah = 2 + (rw & !DEBUG);
307         reg.h.al = 1;
308         reg.x.cx = 1;   /* sector=0  is  sect=1, hd=0, cyl=0 */
309         reg.h.dh = 0;
310         reg.h.dl = bios;
311         reg.x.bx = (word)buffer;
312         /* ES is set == DS */
313         int86x(0x13, &reg, &oreg, &sreg);
314         code = oreg.h.ah;
315         if ((err = (oreg.x.cflag || oreg.h.ah))) {
316             setup(0);
317             reg.h.dl = bios;
318             if (bios & 0x80) reg.h.ah = 0x0D;
319             int86(0x13, &reg, &oreg);
320             --errcnt;
321         }
322     } /* while (err && errcnt) */
323     if (err) {
324         printf("Disk error on 0x%02x, AH = 0x%02x\n", bios, code);
325         exit(1);
326     }
327     return code;
328 }
329
330 void disk_data(int bios)
331 {
332     if (!disk_rw0(bios, RD, buffer.x.sector)) {
333         printf("   %02x   %08lx\n", bios, buffer.x.dsector[110]);
334     }
335 }
336
337 void main(void)
338 {
339     int m, i, dev;
340     char cp[CL_LENGTH];
341     
342     if (!is_msdos()) {
343         video_fix();    /* for Dumb DELL computers */
344     }
345 #if DEBUG>=1 && __MSDOS__==0
346     printf("Beginning of '___cstartup'\n");
347     print_regs(&__argr);
348     printf("DS=%04x  ES=%04x  CS=%04x  SS=%04x  SP=%04x  BP=%04x\n",
349         __argseg.ds, __argseg.es, __argseg.cs, __argseg.ss,
350         __argr.x.flags, __argr.x.cflag);
351         
352     segread(&sreg);
353     printf("\nBeginning of '_main'\n");
354     print_sregs(&sreg);
355 #endif
356     banner(DISK_VERSION);
357     get_cmdline(cp);
358     printf("Command line: '%s'   time=%ld\n", cp, time(NULL));   
359     num_hd = num_hard_disks();
360     printf("The BIOS reports %d hard disks.\n", num_hd);
361     for (i=0; i<num_hd; i++) disk_data(0x80+i);
362     
363     if (!is_msdos()) {
364         pause();
365     }
366 }