Merge branch 'vendor/GDB' into gdb7
[dragonfly.git] / usr.bin / doscmd / intff.c
1 /*
2  * Copyright (c) 1992, 1993, 1996
3  *      Berkeley Software Design, Inc.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by Berkeley Software
16  *      Design, Inc.
17  *
18  * THIS SOFTWARE IS PROVIDED BY Berkeley Software Design, Inc. ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED.  IN NO EVENT SHALL Berkeley Software Design, Inc. BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  *      BSDI intff.c,v 2.2 1996/04/08 19:32:56 bostic Exp
31  *
32  * $FreeBSD: src/usr.bin/doscmd/intff.c,v 1.7.2.2 2002/04/25 11:04:51 tg Exp $
33  * $DragonFly: src/usr.bin/doscmd/intff.c,v 1.2 2003/06/17 04:29:26 dillon Exp $
34  */
35
36 #include <sys/param.h>
37 #include <ctype.h>
38 #include <unistd.h>
39
40 #include "doscmd.h"
41 #include "cwd.h"
42 #include "dispatch.h"
43
44 static LOL      *lol = 0;               /* DOS list-of-lists */
45 static SDA      *sda = 0;               /* DOS swappable data area */
46
47 /******************************************************************************
48 ** redirector functions
49 **
50 **
51 ** These are set up on entry to the redirector each time, and are referenced
52 ** by the functions here.
53 */
54 static int      r_drive,n_drive = 0;
55 static CDS      *r_cds;
56 static SFT      *r_sft;
57
58
59 /*
60 ** 2f:11:0
61 **
62 ** Installation check
63 */
64 static int
65 int2f11_00(regcontext_t *REGS)
66 {
67     R_AL = 0xff;
68     R_AH = 'U';         /* and why not? 8) */
69     return(0);
70 }
71
72 /*
73 ** 2f:11:1 2f:11:2 2f:11:3 2f:11:4 2f:11:5 2f:11:11 2f:11:13
74 **
75 ** Directory functions
76 */
77 static int
78 int2f11_dirfn(regcontext_t *REGS)
79 {
80     char        fname[PATH_MAX], tname[PATH_MAX];
81     int         error;
82
83     error = translate_filename(sda->filename1, fname, &r_drive);
84     if (error)
85         return(error);
86     
87     if (dos_readonly(r_drive) && (R_AL != 0x05))
88         return(WRITE_PROT_DISK);
89
90     switch(R_AL) {
91     case 0x01:                          /* rmdir */
92     case 0x02:
93         debug(D_REDIR,"rmdir(%s)\n",fname);
94         error = rmdir(fname);
95         break;
96     case 0x03:                          /* mkdir */
97     case 0x04:
98         debug(D_REDIR,"mkdir(%s)\n",fname);
99         error = mkdir(fname,0777);
100         break;
101     case 0x05:                          /* chdir */
102         debug(D_REDIR,"chdir(%s)\n",fname);
103         /* Note returns DOS error directly */
104         return(dos_setcwd(sda->filename1));
105         
106     case 0x11:                          /* rename */
107         error = translate_filename(sda->filename2, tname, &r_drive);
108         if (!error) {
109             debug(D_REDIR,"rename(%s,%s)\n",fname,tname);
110             error = rename(fname, tname);
111         }
112         break;
113
114     case 0x13:                          /* unlink */
115         debug(D_REDIR,"unlink(%s)\n",fname);
116         error = unlink(fname);
117         break;
118         
119     default:
120         fatal("called int2f11_dirfn on unknown function %x\n",R_AL);
121     }
122     
123     if (error < 0) {
124         switch(errno) {
125         case ENOTDIR:
126         case ENOENT:
127             return(PATH_NOT_FOUND);
128         case EXDEV:
129             return(NOT_SAME_DEV);
130         default:
131             return(ACCESS_DENIED);
132         }
133     }
134     return(0);
135 }
136
137 /*
138 ** 2f:11:6
139 **
140 ** Close
141 */
142 static int
143 int2f11_close(regcontext_t *REGS __unused)
144 {
145     int         fd;
146
147     fd = r_sft->fd;
148     debug(D_REDIR, "close(%d)\n", fd);
149     
150     r_sft->nfiles--;
151     if (r_sft->nfiles) {
152         debug(D_REDIR, "not last close\n");
153         return(0);
154     }
155     if (close(fd) < 0)
156         return(HANDLE_INVALID);
157     return(0);
158 }
159
160 /*
161 ** 2f:11:8 2f:11:9
162 **
163 ** read/write
164 */
165 static int
166 int2f11_rdwr(regcontext_t *REGS __unused)
167 {
168     int         fd;
169     char        *addr;
170     int         nbytes;
171     int         n = 0;
172
173     fd = r_sft->fd;
174     if (lseek(fd, r_sft->offset, SEEK_SET) < 0)
175         return(SEEK_ERROR);
176
177     addr = (char *)MAKEPTR(sda->dta_seg, sda->dta_off);
178     nbytes = R_CX;
179     
180     switch(R_AL) {
181     case 0x08:                          /* read */
182         debug(D_REDIR, "read(%d, %d)\n", fd, nbytes);
183         n = read(fd, addr, nbytes);
184         if (n < 0)
185             return(READ_FAULT);
186         break;
187     case 0x09:
188         debug(D_REDIR, "write(%d, %d)\n", fd, nbytes);
189         n = write(fd, addr, nbytes);
190         if (n < 0)
191             return(WRITE_FAULT);
192         break;
193     default:
194         fatal("called int2f11_rdwr on unknown function %x\n",R_AL);
195     }
196     
197     R_CX = n;                           /* report count */
198     r_sft->offset += n;
199     if (r_sft->offset > r_sft->size)
200         r_sft->size = r_sft->offset;
201     debug(D_REDIR, "offset now %ld\n", r_sft->offset);
202     return(0);
203 }
204
205 /*
206 ** 2f:11:c
207 **
208 ** Get free space (like 21:36)
209 */
210 static int
211 int2f11_free(regcontext_t *REGS __unused)
212 {
213     fsstat_t    fs;
214     int         error;
215     
216     error = get_space(r_drive, &fs);
217     if (error)
218         return (error);
219     R_AX = fs.sectors_cluster;
220     R_BX = fs.total_clusters;
221     R_CX = fs.bytes_sector;
222     R_DX = fs.avail_clusters;
223     return(0);
224 }
225
226 /*
227 ** 2f:11:f
228 **
229 ** get size and mode
230 */
231 static int
232 int2f11_stat(regcontext_t *REGS __unused)
233 {
234     char        fname[PATH_MAX];
235     struct stat sb;
236     int         error;
237     
238     error = translate_filename(sda->filename1, fname, &r_drive);
239     if (error)
240         return(error);
241     
242     if (stat(fname, &sb) < 0)
243         return(FILE_NOT_FOUND);
244     
245     R_AX = to_dos_attr(sb.st_mode);
246     R_BX = sb.st_size >> 16;
247     R_DI = sb.st_size & 0xffff;
248     return(0);
249 }
250
251 /*
252 ** 2f:11:16 2f:11:17 2f:11:18 2f:11:2e
253 **
254 ** Open/create a file, closely resembles int21_open.
255 */
256 static int
257 int2f11_open(regcontext_t *REGS)
258 {
259     char        fname[PATH_MAX];
260     struct stat sb;
261     int         error;
262     int         mode = 0;               /* open mode */
263     int         attr;                   /* attributes of created file */
264     int         action = 0;             /* what to do about file */
265     u_char      *p, *e;
266     int         i;
267     int         omode = 0;              /* mode to say we opened in */
268     int         status;
269     int         fd;
270     
271     error = translate_filename(sda->filename1, fname, &r_drive);
272     if (error)
273         return(error);
274
275     /* 
276     ** get attributes/access mode off stack : low byte is attribute, high
277     ** byte is (sometimes) used in conjunction with 'action'
278     */
279     attr = *(u_short *)MAKEPTR(R_SS, R_SP) & 0xff;
280
281     /* which style? */
282     switch(R_AL) {
283     case 0x16:                          /* open */
284         action = 0x01;                  /* fail if does not exist */
285         switch (sda->open_mode & 3) {
286         case 0:
287             mode = O_RDONLY;
288             break;
289         case 1:
290             mode = O_WRONLY;
291             break;
292         case 2:
293             mode = O_RDWR;
294             break;
295         default:
296             return (FUNC_NUM_IVALID);
297         }
298         omode = sda->open_mode & 0x7f;
299         debug(D_REDIR,"open");
300         break;
301
302     case 0x17:                          /* creat/creat new */
303     case 0x18:                          /* creat/creat new (no CDS, but we don't care)*/
304         mode = O_RDWR;
305         omode = 3;
306         if (attr & 0x100) {             /* creat new */
307             action = 0x10;              /* create if not exist, fail if exists */
308             debug(D_REDIR, "creat_new");
309         } else {                        /* creat */
310             action = 0x12;              /* create and destroy */
311             debug(D_REDIR, "creat");
312         }
313         break;
314
315     case 0x2e:                          /* multipurpose */
316         attr = sda->ext_attr;
317         action = sda->ext_action;
318         switch (sda->ext_mode & 3) {
319         case 0:
320             mode = O_RDONLY;
321             break;
322         case 1:
323             mode = O_WRONLY;
324             break;
325         case 2:
326             mode = O_RDWR;
327             break;
328         default:
329             return (FUNC_NUM_IVALID);
330         }
331         omode = sda->ext_mode & 0x7f;
332         debug(D_REDIR,"mopen");
333         break;
334
335     default:
336         fatal("called int2f11_open for unknown function %x\n",R_AL);
337     }
338     if (action & 0x02)  /* replace/open mode */
339         mode |= O_TRUNC;
340     debug(D_REDIR, "(%s) action 0x%x  mode 0x%x  attr 0x%x omode 0x%x \n", 
341           fname, action, mode, attr, omode);
342         
343     if (ustat(fname, &sb) < 0) {                        /* file does not exist */
344         if ((action & 0x10) || (attr & 0x100)) {        /* create it */
345             sb.st_ino = 0;
346             mode |= O_CREAT;                            /* have to create as we go */
347             status = 0x02;                              /* file created */
348         } else {
349             return(FILE_NOT_FOUND);                     /* fail */
350         }
351     } else {
352         if (S_ISDIR(sb.st_mode))
353             return(ACCESS_DENIED);
354         if ((action & 0x03) && !(attr & 0x100)) {       /* exists, work with it */
355             if (action & 0x02) {
356                 if (!S_ISREG(sb.st_mode)) {             /* only allowed for files */
357                     debug(D_FILE_OPS,"attempt to truncate non-regular file\n");
358                     return(ACCESS_DENIED);
359                 }
360                 status = 0x03;                          /* we're going to truncate it */
361             } else {
362                 status = 0x01;                          /* just open it */
363             }
364         } else {
365             return(FILE_ALREADY_EXISTS);                /* exists, fail */
366         }
367     }
368
369     if ((fd = open(fname, mode, from_dos_attr(attr))) < 0) {
370         debug(D_FILE_OPS,"failed to open %s : %s\n",fname,strerror(errno));
371         return (ACCESS_DENIED);
372     }
373
374     if (R_AL == 0x2e)                   /* extended wants status returned */
375         R_CX = status;
376
377     /* black magic to populate the SFT */
378
379     e = p = sda->filename1 + 2;         /* parse name */
380     while (*p) {
381         if (*p++ == '\\')               /* look for beginning of filename */
382             e = p;
383     }
384
385     for (i = 0; i < 8; ++i) {           /* copy name and pad with spaces */
386         if (*e && *e != '.')
387             r_sft->name[i] = *e++;
388         else
389             r_sft->name[i] = ' ';
390     }
391
392     if (*e == '.')                      /* skip period on short names */
393         ++e;
394     
395     for (i = 0; i < 3; ++i) {           /* copy extension and pad with spaces */
396         if (*e)
397             r_sft->ext[i] = *e++;
398         else
399             r_sft->ext[i] = ' ';
400     }
401
402     if (ustat(fname, &sb) < 0)          /* re-stat to be accurate */
403         return(WRITE_FAULT);            /* any better ideas?! */
404
405     r_sft->open_mode = omode;           /* file open mode */
406     *(u_long *)r_sft->ddr_dpb = 0;      /* no parameter block */
407     r_sft->size = sb.st_size;           /* current size */
408     r_sft->fd = fd;                     /* our fd for it (hidden in starting cluster number) */
409     r_sft->offset = 0;                  /* current offset is 0 */
410     *(u_short *)r_sft->dir_sector = 0;  /* not local file, ignored */
411     r_sft->dir_entry = 0;               /* not local file, ignored */
412     r_sft->attribute = attr & 0xff;     /* file attributes as requested */
413     r_sft->info = r_drive + 0x8040;     /* hide drive number here for later reference */
414     encode_dos_file_time(sb.st_mtime, &r_sft->date, &r_sft->time);
415     debug(D_REDIR,"success, fd %d  status %x\n", fd, status);
416     return(0);
417 }
418
419 /*
420 ** 2f:11:19 2f:11:1b
421 **
422 ** find first
423 */
424 static int
425 int2f11_findfirst(regcontext_t *REGS __unused)
426 {
427     return(find_first(sda->filename1,sda->attrmask,
428                       (dosdir_t *)sda->foundentry,
429                       (find_block_t *)sda->findfirst));
430 }
431
432 /*
433 ** 2f:11:1c
434 **
435 ** find next
436 */
437 static int
438 int2f11_findnext(regcontext_t *REGS __unused)
439 {
440     return(find_next((dosdir_t *)sda->foundentry,
441                      (find_block_t *)sda->findfirst));
442 }
443
444 /*
445 ** 2f:11:21
446 **
447 ** lseek
448 */
449 static int
450 int2f11_lseek(regcontext_t *REGS)
451 {
452     int         fd;
453     off_t       offset;
454
455     fd = r_sft->fd;
456     offset = (off_t) ((int) ((R_CX << 16) + R_DX));
457     
458     debug(D_REDIR,"lseek(%d, 0x%qx, SEEK_END)\n", fd, offset);
459     
460     if ((offset = lseek(fd, offset, SEEK_END)) < 0) {
461         if (errno == EBADF)
462             return(HANDLE_INVALID);
463         else
464             return(SEEK_ERROR);
465     }
466     r_sft->offset = offset;             /* update offset in SFT */
467     R_DX = offset >> 16;
468     R_AX = offset;
469     return(0);
470 }
471
472 /*
473 ** 2f:11:23
474 **
475 ** qualify filename
476 */
477 static int
478 int2f11_fnqual(regcontext_t *REGS)
479 {
480     char        *fname;
481     char        *tname;
482     static char errmsg[] = "(failed)";
483     int         savedrive;
484     int         error;
485
486     return(PATH_NOT_FOUND);
487     
488     savedrive = diskdrive;              /* to get CWD for network drive */
489     diskdrive = n_drive;
490     fname = (char *)MAKEPTR(R_DS, R_SI);        /* path pointers */
491     tname = (char *)MAKEPTR(R_ES, R_DI);
492     
493     error = dos_makepath(fname, tname);
494     if (error)
495         tname = errmsg;
496
497     diskdrive = savedrive;              /* restore correct drive */
498     
499     debug(D_REDIR, "qualify '%s' -> '%s'\n", fname, tname);
500     return(error);
501 }
502
503 /*
504 ** 2f:11:??
505 **
506 ** Null function - we know about it but do nothing
507 */
508 static int
509 int2f11_NULLFUNC(regcontext_t *REGS __unused)
510 {
511     return(0);
512 }
513
514 /*
515 ** 2f:11:??
516 **
517 ** no function - not handled here (error)
518 */
519 static int
520 int2f11_NOFUNC(regcontext_t *REGS __unused)
521 {
522     return(-1);
523 }
524
525 struct intfunc_table int2f11_table[] = {
526     { 0x00,     IFT_NOSUBFUNC,  int2f11_00,             "installation check"},
527     { 0x01,     IFT_NOSUBFUNC,  int2f11_dirfn,          "rmdir"},
528     { 0x02,     IFT_NOSUBFUNC,  int2f11_dirfn,          "rmdir"},
529     { 0x03,     IFT_NOSUBFUNC,  int2f11_dirfn,          "mkdir"},
530     { 0x04,     IFT_NOSUBFUNC,  int2f11_dirfn,          "mkdir"},
531     { 0x05,     IFT_NOSUBFUNC,  int2f11_dirfn,          "chdir"},
532     { 0x06,     IFT_NOSUBFUNC,  int2f11_close,          "close"},
533     { 0x07,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "commit file"},
534     { 0x08,     IFT_NOSUBFUNC,  int2f11_rdwr,           "read"},
535     { 0x09,     IFT_NOSUBFUNC,  int2f11_rdwr,           "write"},
536     { 0x0a,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "lock region"},
537     { 0x0b,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "unlock region"},
538     { 0x0c,     IFT_NOSUBFUNC,  int2f11_free,           "free space"},
539     { 0x0e,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "chmod"},
540     { 0x0f,     IFT_NOSUBFUNC,  int2f11_stat,           "stat"},
541     { 0x11,     IFT_NOSUBFUNC,  int2f11_dirfn,          "rename"},
542     { 0x13,     IFT_NOSUBFUNC,  int2f11_dirfn,          "unlink"},
543     { 0x16,     IFT_NOSUBFUNC,  int2f11_open,           "open"},
544     { 0x17,     IFT_NOSUBFUNC,  int2f11_open,           "creat"},
545     { 0x18,     IFT_NOSUBFUNC,  int2f11_open,           "creat"},
546     { 0x19,     IFT_NOSUBFUNC,  int2f11_findfirst,      "find first"},
547     { 0x1b,     IFT_NOSUBFUNC,  int2f11_findfirst,      "find first"},
548     { 0x1c,     IFT_NOSUBFUNC,  int2f11_findnext,       "find next"},
549     { 0x1d,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "close all (abort)"},
550     { 0x1e,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "do redirection"},
551     { 0x1f,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "printer setup"},
552     { 0x20,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "flush all buffers"},
553     { 0x21,     IFT_NOSUBFUNC,  int2f11_lseek,          "lseek"},
554     { 0x22,     IFT_NOSUBFUNC,  int2f11_NULLFUNC,       "process terminated"},
555     { 0x23,     IFT_NOSUBFUNC,  int2f11_fnqual,         "qualify filename"},
556     { 0x24,     IFT_NOSUBFUNC,  int2f11_NOFUNC,         "turn off printer"},
557     { 0x25,     IFT_NOSUBFUNC,  int2f11_NOFUNC,         "printer mode"},
558     { 0x2d,     IFT_NOSUBFUNC,  int2f11_NOFUNC,         "extended attributes"},
559     { 0x2e,     IFT_NOSUBFUNC,  int2f11_open,           "extended open/create"},
560     { -1,       0,              NULL,                   NULL}
561 };
562
563 static int int2f11_fastlookup[256];
564
565 /******************************************************************************
566 ** 2f:11
567 **
568 ** The DOS redirector interface.
569 */
570
571 /*
572 ** Verify that the drive being referenced is one we are handling, and
573 ** establish some state for upcoming functions.
574 ** 
575 ** Returns 1 if we should handle this request.
576 **
577 ** XXX this is rather inefficient, but much easier to read than the previous
578 ** incarnation 8(
579 */
580 static int
581 int2f11_validate(regcontext_t *REGS)
582 {
583     int         func = R_AL;
584     const char  *path = NULL;
585     int         doit = 0;
586
587     /* defaults may help trap problems */
588     r_cds = NULL;
589     r_sft = NULL;
590     r_drive = -1;
591     
592     /* some functions we accept regardless */
593     switch (func) {
594     case 0x00:          /* installation check */
595     case 0x23:          /* qualify path */
596     case 0x1c:          /* XXX really only valid if a search already started... */
597         return(1);
598     }
599     
600     /* Where's the CDS? */
601     switch(func) {
602     case 0x01:          /* referenced by the SDA */
603     case 0x02:
604     case 0x03:
605     case 0x04:
606     case 0x05:
607     case 0x0e:
608     case 0x0f:
609     case 0x11:
610     case 0x13:
611     case 0x17:
612     case 0x1b:
613         r_cds = (CDS *)MAKEPTR(sda->cds_seg, sda->cds_off);
614         break;
615
616     case 0x0c:          /* in es:di */
617     case 0x1c:
618         r_cds = (CDS *)MAKEPTR(R_ES, R_DI);
619         break;
620     }
621
622     /* Where's the SFT? */
623     switch(func) {
624     case 0x06:          /* in es:di */
625     case 0x07:
626     case 0x08:
627     case 0x09:
628     case 0x0a:
629     case 0x0b:
630     case 0x16:
631     case 0x17:
632     case 0x18:
633     case 0x21:
634     case 0x2d:
635     case 0x2e:
636         r_sft = (SFT *)MAKEPTR(R_ES, R_DI);
637         break;
638     }
639     
640     /* What drive? */
641     switch(func) {
642     case 0x01:          /* get drive from fully-qualified path in SDA */
643     case 0x02:
644     case 0x03:
645     case 0x04:
646     case 0x05:
647     case 0x0c:
648     case 0x0e:
649     case 0x0f:
650     case 0x11:
651     case 0x13:
652     case 0x16:
653     case 0x17:
654     case 0x18:
655     case 0x19:
656     case 0x1b:
657     case 0x2e:
658         path = sda->filename1;
659         break;
660         
661     case 0x06:          /* get drive from SFT (we put it here when file was opened) */
662     case 0x07:
663     case 0x08:
664     case 0x09:
665     case 0x0a:
666     case 0x0b:
667     case 0x21:
668     case 0x2d:
669         r_drive = r_sft->info & 0x1f;
670         break;
671     }
672
673     if (path) {         /* we have a path and need to determine the drive it refers to */
674
675         if (path[1] != ':') {   /* must be fully qualified; we cannot handle this */
676             debug(D_REDIR,"attempt to work non-absolute path %s\n",path);
677             return(0);
678         }
679
680         /* translate letter to drive number */
681         r_drive = drlton(path[0]);
682     } else {
683         path = "(no path)";
684     }
685         
686     /* do we handle this drive? */
687     if (dos_getcwd(r_drive)) {
688         n_drive = r_drive;              /* XXX GROSTIC HACK ALERT */
689         doit = 1;
690     }
691     
692     debug(D_REDIR,"%s -> drive %c func %x (%sus)\n",
693           path, drntol(r_drive), func, doit?"":"not ");
694     
695     /* so do we deal with this one? */
696     return(doit);
697 }
698
699     
700 int 
701 int2f_11(regcontext_t *REGS)
702 {
703     int         idx;
704     int         error;
705     
706     if (!sda) {         /* not initialised yet */
707         error = FUNC_NUM_IVALID;
708     } else {
709
710         idx = intfunc_find(int2f11_table, int2f11_fastlookup, R_AL, 0);
711         if (idx == -1) {
712             debug(D_ALWAYS,"no handler for int2f:11:%x\n", R_AL);
713             return(0);
714         }
715         reset_poll();
716         
717
718         if (!int2f11_validate(REGS)) {          /* determine whether we handle this request */
719             error = -1;                         /* not handled by us */
720         } else {
721             debug(D_REDIR, "REDIR: %02x (%s)\n", 
722                       int2f11_table[idx].func, int2f11_table[idx].desc);
723             /* call the handler */
724             error = int2f11_table[idx].handler(REGS);
725             if (error != -1)
726                 debug(D_REDIR, "REDIR: returns %d (%s)\n", 
727                       error, ((error >= 0) && (error <= dos_ret_size)) ? dos_return[error] : "unknown");
728         }
729     }
730
731     if (error == -1)
732         return (0);
733     if (error) {
734         R_AX = error;
735         R_FLAGS |= PSL_C;
736     } else
737         R_FLAGS &= ~PSL_C;
738     return (1);
739 }
740
741 /******************************************************************************
742 ** intff handler.
743 **
744 ** intff is the (secret, proprietary, internal, evil) call to 
745 ** initialise the redirector.
746 */
747 static void
748 install_drive(int drive, u_char *path)
749 {
750     CDS *cds;
751
752     /* check that DOS considers this a valid drive */
753     if (drive < 0 || drive >= lol->lastdrive) {
754         debug(D_REDIR, "Drive %c beyond limit of %c\n",
755               drntol(drive), drntol(lol->lastdrive - 1));
756         return;
757     }
758
759     /* get the CDS for this drive */
760     cds = (CDS *)MAKEPTR(lol->cds_seg, lol->cds_offset);
761     cds += drive;
762
763 #if 0   /* XXX looks OK to me - mjs */
764     if (cds->flag & (CDS_remote | CDS_ready)) {
765         debug(D_REDIR, "Drive %c already installed\n", drntol(drive));
766         return;
767     }
768 #endif
769
770     debug(D_REDIR, "Installing %c: as %s\n", drntol(drive), path);
771
772     cds->flag |= CDS_remote | CDS_ready | CDS_notnet;
773     cds->path[0] = drntol(drive);
774     cds->path[1] = ':';
775     cds->path[2] = '\\';
776     cds->path[3] = '\0';
777     cds->offset = 2;    /* offset of \ in current path field */
778 }
779
780 static void
781 init_drives(void)
782 {
783     int drive;
784     u_char *path;
785
786     /* for all possible drives */
787     for (drive = 0; drive < 26; ++drive) {
788         if ((path = dos_getpath(drive)) != 0)   /* assigned to a path? */
789             install_drive(drive, path);         /* make it visible to DOS */
790     }   
791 }
792
793
794 void
795 intff(regcontext_t *REGS)
796 {
797
798     if (lol && sda) {                           /* already been called? */
799         debug(D_REDIR, "redirector duplicate install ignored");
800         return;
801     }
802     lol = (LOL *)MAKEPTR(R_BX, R_DX);   /* where DOS keeps its goodies */
803     sda = (SDA *)MAKEPTR(R_DI, R_SI);
804     init_drives();
805     
806     /* initialise dispatcher */
807     intfunc_init(int2f11_table, int2f11_fastlookup);
808 }