ceh.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. /* $Id$
  2. * MegaZeux
  3. *
  4. * Copyright (C) 1996 Greg Janson
  5. * Copyright (C) 1998 Matthew D. Williams - dbwilli@scsn.net
  6. *
  7. * This program is free software; you can redistribute it and/or
  8. * modify it under the terms of the GNU General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  15. * General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. */
  21. /*
  22. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿
  23. ³ CRITICAL ERROR HANDLER ³
  24. ³ ³
  25. ³ The Critical Error Handler or CEH as it is also called is ³
  26. ³ a software routine that attempts to recover from a variety ³
  27. ³ of internal and external errors that would prevent program ³
  28. ³ continuance. ³
  29. ³ ³
  30. ³ Consider this example. A program wants to open a file and ³
  31. ³ issues the DOS services interrupt (interrupt 21h) with the ³
  32. ³ "open file" function code in AH (3Dh). This file is found ³
  33. ³ on a floppy disk in the A: drive. However, the drive door ³
  34. ³ handle has been left open. What happens? ³
  35. ³ ³
  36. ³ Once interrupt 21h is issued, the DOS kernel takes over. ³
  37. ³ The kernel calls a device driver. The device driver calls ³
  38. ³ the BIOS. The BIOS communicates with the disk controller ³
  39. ³ via the IN and OUT machine language instructions. Because ³
  40. ³ the controller cannot read the disk, it sends error infor- ³
  41. ³ mation to the BIOS. The BIOS sends error information to ³
  42. ³ the device driver. The device driver sends error infor- ³
  43. ³ mation to the kernel. At this point, the DOS designers ³
  44. ³ could have done one of two things. The kernel could have ³
  45. ³ always sent the error information to the program causing ³
  46. ³ it to deal with the error (the FAIL option) or the kernel ³
  47. ³ could have made an attempt to solve the problem with user ³
  48. ³ help (the ABORT, RETRY, IGNORE, FAIL prompt). This latter ³
  49. ³ approach was chosen and is more flexible than the previous ³
  50. ³ approach. The user has the opportunity of closing the ³
  51. ³ door handle and selecting RETRY. This time, the operation ³
  52. ³ should succeed. ³
  53. ³ ³
  54. ³ The ABORT option causes DOS to return to the COMMAND.COM ³
  55. ³ drive prompt. This option could be disasterous if a file ³
  56. ³ has been opened by the program and information written to ³
  57. ³ the file but still in a DOS holding buffer. When ABORT is ³
  58. ³ chosen, the information in the buffer is not written to ³
  59. ³ this file and the file is not properly closed (with its ³
  60. ³ directory entry updated). ³
  61. ³ ³
  62. ³ RETRY allows the DOS kernel to attempt the operation again ³
  63. ³ but this option is generally only useful if the problem is ³
  64. ³ due to leaving a drive handle open or the printer offline. ³
  65. ³ Simply closing the handle or placing the printer online is ³
  66. ³ all that is needed to get the program running again. ³
  67. ³ ³
  68. ³ The IGNORE option is a form of gambling. The DOS kernel ³
  69. ³ is told to ignore the error and let the program continue. ³
  70. ³ If the kernel does not feel that the error is that serious ³
  71. ³ then it will allow the program to continue. ³
  72. ³ ³
  73. ³ DOS 3.3 added the FAIL option (better than IGNORE). FAIL ³
  74. ³ tells the kernel to allow the program to continue but pass ³
  75. ³ back an error code via interrupt 21h to the program allow- ³
  76. ³ ing it to make the decision as to continuing or not. ³
  77. ³ ³
  78. ³ Upon entry to interrupt 24h (the critical error handler), ³
  79. ³ certain registers contain values indicating the nature of ³
  80. ³ the error and what course of action should be taken. Reg- ³
  81. ³ isters AH, AL, BP:SI, and DI contain this information. ³
  82. ³ ³
  83. ³ If bit 7 of AH is 0 then the error was caused by a disk ³
  84. ³ operation and is known as a hard error. The failing drive ³
  85. ³ number is placed in AL (0 = A, 1 = B, 2 = C, etc). If bit ³
  86. ³ 5 is 1 then the IGNORE option is allowed. If bit 4 is 1 ³
  87. ³ then the RETRY option is allowed. If bit 3 is 1 then the ³
  88. ³ FAIL option is allowed. FAIL is not allowed on versions ³
  89. ³ prior to 3.3 and IGNORE may not be allowed on versions 3.3 ³
  90. ³ and higher because FAIL is present. RETRY is allowed in ³
  91. ³ versions 3.3 and higher. Bits 2 and 1 contain a code that ³
  92. ³ indicates the affected disk area. A "0 0" indicates DOS, ³
  93. ³ a "0 1" indicates the file allocation table (FAT), a "1 0" ³
  94. ³ indicates the directory, and a "1 1" indicates the data ³
  95. ³ area. If bit 0 is 1 then the operation that was taking ³
  96. ³ place when the error occured was a write otherwise it was ³
  97. ³ a read. ³
  98. ³ ³
  99. ³ If bit 7 of AH is 1 then the error was caused by either a ³
  100. ³ character device such as the printer or a bad memory image ³
  101. ³ of the file allocation table (FAT). BP:SI points to the ³
  102. ³ device header of the failing device. If the high bit of ³
  103. ³ the byte at BP:[SI+4] is 1 then the error is due to a bad ³
  104. ³ FAT image otherwise it is due to a character device. AL ³
  105. ³ contains no useful information if bit 7 of AH is 1. ³
  106. ³ ³
  107. ³ Regardless of what caused the error (disk or device or bad ³
  108. ³ FAT image), the lower-half of DI contains an error code. ³
  109. ³ ³
  110. ³ 00h - write-protect violation ³
  111. ³ 01h - unknown drive number ³
  112. ³ 02h - drive not ready ³
  113. ³ 03h - unknown command (to controller) ³
  114. ³ 04h - CRC data error ³
  115. ³ 05h - bad request structure length ³
  116. ³ 06h - seek error ³
  117. ³ 07h - unknown media (disk) type ³
  118. ³ 08h - sector not found ³
  119. ³ 09h - printer out of paper ³
  120. ³ 0ah - error while writing ³
  121. ³ 0bh - error while reading ³
  122. ³ 0ch - general failure ³
  123. ³ ³
  124. ³ Upon exit, the CEH returns a code in AL to let the kernel ³
  125. ³ know what action to take. ³
  126. ³ ³
  127. ³ 0 - IGNORE ³
  128. ³ 1 - RETRY ³
  129. ³ 2 - ABORT ³
  130. ³ 3 - FAIL ³
  131. ³ ³
  132. ³ Since the CEH is called by the DOS kernel and DOS is not ³
  133. ³ reentrant, only the following interrupt 21h services can ³
  134. ³ be used from inside the handler. The services are 01h to ³
  135. ³ 0ch inclusive (the console I/O functions) and 59h (get the ³
  136. ³ extended error information). Any other service will cause ³
  137. ³ the computer to lock up. ³
  138. ³ ³
  139. ³ The default critical error handler is actually located in ³
  140. ³ the resident portion of the COMMAND.COM TSR. There are a ³
  141. ³ few problems with this handler. First of all, if ABORT is ³
  142. ³ chosen then the program is aborted as control returns to ³
  143. ³ the DOS prompt (and any data waiting to be written to disk ³
  144. ³ never gets there). Secondly, when the handler writes its ³
  145. ³ messages to the screen, these messages can overwrite what- ³
  146. ³ ever is presently on the screen without first saving these ³
  147. ³ contents. The screen is not restored when the handler is ³
  148. ³ finished. These problems are solved by CEH.C. CEH.C con- ³
  149. ³ tains source code for a handler that is more user-friendly ³
  150. ³ that the default. Two options are allowed: RETRY or ABORT ³
  151. ³ (ABORT means FAIL in this case allowing a program to con- ³
  152. ³ tinue and decide if it should exit). DOS 3.3 is required ³
  153. ³ to use this handler because of the FAIL option. ³
  154. ³ ³
  155. ³ This handler was written in BORLAND C++ 2.0 using the C ³
  156. ³ compiler. It has been tested successfully in all memory ³
  157. ³ models. It will undoubtedly work on all BORLAND C compil- ³
  158. ³ ers starting with Turbo C 1.5. Some modifications will be ³
  159. ³ necessary to port this code to other C compilers, notably ³
  160. ³ the console video functions. Here is a quick rundown on ³
  161. ³ these functions. ³
  162. ³ ³
  163. ³ window (int left, int top, int right, int bottom); ³
  164. ³ ³
  165. ³ The console video functions work within a simple windowing ³
  166. ³ environment. The window () function defines the rectangle ³
  167. ³ on the screen where console I/O is performed. The screen ³
  168. ³ coordinates are relative to the upper-left corner of this ³
  169. ³ window and have origin (1, 1). The default window is the ³
  170. ³ size of the screen (1, 1, 40, 25) in 40-column text modes ³
  171. ³ and (1, 1, 80, 25) in 80-column text modes. The CEH pro- ³
  172. ³ gram assumes an 80-column mode but could be converted to ³
  173. ³ support either 80 or 40. ³
  174. ³ ³
  175. ³ gotoxy (int x, int y); ³
  176. ³ ³
  177. ³ This function positions the cursor within the active win- ³
  178. ³ dow to column x and row y. It fails if the coordinates ³
  179. ³ are outside of the window range. ³
  180. ³ ³
  181. ³ wherex (void); ³
  182. ³ ³
  183. ³ This function returns the x-coordinate of the cursor. ³
  184. ³ ³
  185. ³ wherey (void); ³
  186. ³ ³
  187. ³ This function returns the y-coordinate of the cursor. ³
  188. ³ ³
  189. ³ cputs (const char *string); ³
  190. ³ ³
  191. ³ This function writes a string to the window beginning at ³
  192. ³ the current cursor location within the window. Scrolling ³
  193. ³ (vertical) occurs if the string wraps past the lower-right ³
  194. ³ boundary. The current attribute defined by textattr () is ³
  195. ³ used. ³
  196. ³ ³
  197. ³ putch (int character); ³
  198. ³ ³
  199. ³ This function writes a character to the window at the cur- ³
  200. ³ rent cursor location within the window. The cursor loca- ³
  201. ³ tion is updated and the current attribute defined by text- ³
  202. ³ attr () is used. ³
  203. ³ ³
  204. ³ gettext (int left, int top, int right, int bottom, char * ³
  205. ³ buffer); ³
  206. ³ ³
  207. ³ This function uses screen coordinates, not window. It is ³
  208. ³ not restricted to a window. The screen contents bounded ³
  209. ³ by (left, top) and (right, bottom) are read into an array ³
  210. ³ pointed to by buffer. Two bytes are read for each screen ³
  211. ³ position: one for the character and one for the attribute. ³
  212. ³ The puttext () function is similar except that it writes ³
  213. ³ the buffer contents to the screen. ³
  214. ³ ³
  215. ³ textattr (int attribute); ³
  216. ³ ³
  217. ³ Set current drawing attribute used by cputs ()/putch () to ³
  218. ³ attribute. ³
  219. ³ ³
  220. ³ clrscr (void); ³
  221. ³ ³
  222. ³ Clear the contents of the current window. Blanks are used ³
  223. ³ for clearing along with the attribute most recently speci- ³
  224. ³ fied by textattr (). ³
  225. ³ ³
  226. ³ gettextinfo (struct text_info *t); ³
  227. ³ ³
  228. ³ The current windowing state including window boundaries, ³
  229. ³ cursor location, and drawing attribute is read into the t ³
  230. ³ structure. This allows the windowing state to be restored ³
  231. ³ later. ³
  232. ³ ³
  233. ³ There are a few additional modifications to be made. ³
  234. ³ ³
  235. ³ The peekb() macro takes two arguments: segment and offset. ³
  236. ³ It returns the byte found at this location. ³
  237. ³ ³
  238. ³ The setvect () function takes two arguments: an integer ³
  239. ³ identifying the interrupt to be taken over and a pointer ³
  240. ³ to the new interrupt function. ³
  241. ³ ³
  242. ³ The geninterrupt() macro and pseudo-registers (_AH, _ES, ³
  243. ³ etc.) can be replaced via an int86 () function. ³
  244. ³ ³
  245. ³ The _osmajor and _osminor global variables contain the ³
  246. ³ major and minor portions of the DOS version number respec- ³
  247. ³ tively. A call to interrupt 21h with function 30h placed ³
  248. ³ in AH will return the major portion in AL and the minor in ³
  249. ³ AH. ³
  250. ³ ³
  251. ³ Written by: Geoff Friesen, November 1991 ³
  252. ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
  253. */
  254. #include "ceh.h"
  255. #include <dos.h>
  256. #include "error.h"
  257. #include "data.h"
  258. #define RETRY 1
  259. #define FAIL 3
  260. static char *errmsgs [] =
  261. {
  262. "Disk is write-protected.",
  263. "Unknown drive number.",
  264. "Drive not ready.",
  265. "Disk controller does not recognize command.",
  266. "Data integrity error.",
  267. "Poorly organized data passed to disk controller.",
  268. "Seek error.",
  269. "Disk type is unknown.",
  270. "Sector not found.",
  271. "Printer out of paper.",
  272. "Could not write.",
  273. "Could not read.",
  274. "General failure - disk might need formatting.",
  275. "Internal error."
  276. };
  277. #pragma warn -par
  278. static void interrupt ceh (unsigned bp, unsigned di, unsigned si,
  279. unsigned ds, unsigned es, unsigned dx,
  280. unsigned cx, unsigned bx, unsigned ax)
  281. {
  282. unsigned i;
  283. i=(di > 12) ? 13 : di;
  284. i=error2(errmsgs[i],3,7,current_pg_seg,0);
  285. ax=(i==1)?FAIL:RETRY;
  286. }
  287. #pragma warn +par
  288. void installceh (void)
  289. {
  290. if (_osmajor < 3 || (_osmajor == 3 && _osminor < 3))
  291. return;
  292. setvect (0x24, ceh);
  293. return;
  294. }