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