Nuke unused macro and comment
[dragonfly.git] / usr.bin / doscmd / intff.c
blob930f7f9d6b5f99d54e0b9b91233068424b631df3
1 /*
2 * Copyright (c) 1992, 1993, 1996
3 * Berkeley Software Design, Inc. All rights reserved.
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.
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.
30 * BSDI intff.c,v 2.2 1996/04/08 19:32:56 bostic Exp
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 $
36 #include <sys/param.h>
37 #include <ctype.h>
38 #include <unistd.h>
40 #include "doscmd.h"
41 #include "cwd.h"
42 #include "dispatch.h"
44 static LOL *lol = 0; /* DOS list-of-lists */
45 static SDA *sda = 0; /* DOS swappable data area */
47 /******************************************************************************
48 ** redirector functions
51 ** These are set up on entry to the redirector each time, and are referenced
52 ** by the functions here.
54 static int r_drive,n_drive = 0;
55 static CDS *r_cds;
56 static SFT *r_sft;
60 ** 2f:11:0
62 ** Installation check
64 static int
65 int2f11_00(regcontext_t *REGS)
67 R_AL = 0xff;
68 R_AH = 'U'; /* and why not? 8) */
69 return(0);
73 ** 2f:11:1 2f:11:2 2f:11:3 2f:11:4 2f:11:5 2f:11:11 2f:11:13
75 ** Directory functions
77 static int
78 int2f11_dirfn(regcontext_t *REGS)
80 char fname[PATH_MAX], tname[PATH_MAX];
81 int error;
83 error = translate_filename(sda->filename1, fname, &r_drive);
84 if (error)
85 return(error);
87 if (dos_readonly(r_drive) && (R_AL != 0x05))
88 return(WRITE_PROT_DISK);
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));
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);
112 break;
114 case 0x13: /* unlink */
115 debug(D_REDIR,"unlink(%s)\n",fname);
116 error = unlink(fname);
117 break;
119 default:
120 fatal("called int2f11_dirfn on unknown function %x\n",R_AL);
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);
134 return(0);
138 ** 2f:11:6
140 ** Close
142 static int
143 int2f11_close(regcontext_t *REGS __unused)
145 int fd;
147 fd = r_sft->fd;
148 debug(D_REDIR, "close(%d)\n", fd);
150 r_sft->nfiles--;
151 if (r_sft->nfiles) {
152 debug(D_REDIR, "not last close\n");
153 return(0);
155 if (close(fd) < 0)
156 return(HANDLE_INVALID);
157 return(0);
161 ** 2f:11:8 2f:11:9
163 ** read/write
165 static int
166 int2f11_rdwr(regcontext_t *REGS __unused)
168 int fd;
169 char *addr;
170 int nbytes;
171 int n;
173 fd = r_sft->fd;
174 if (lseek(fd, r_sft->offset, SEEK_SET) < 0)
175 return(SEEK_ERROR);
177 addr = (char *)MAKEPTR(sda->dta_seg, sda->dta_off);
178 nbytes = R_CX;
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);
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);
206 ** 2f:11:c
208 ** Get free space (like 21:36)
210 static int
211 int2f11_free(regcontext_t *REGS __unused)
213 fsstat_t fs;
214 int error;
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);
227 ** 2f:11:f
229 ** get size and mode
231 static int
232 int2f11_stat(regcontext_t *REGS __unused)
234 char fname[PATH_MAX];
235 struct stat sb;
236 int error;
238 error = translate_filename(sda->filename1, fname, &r_drive);
239 if (error)
240 return(error);
242 if (stat(fname, &sb) < 0)
243 return(FILE_NOT_FOUND);
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);
252 ** 2f:11:16 2f:11:17 2f:11:18 2f:11:2e
254 ** Open/create a file, closely resembles int21_open.
256 static int
257 int2f11_open(regcontext_t *REGS)
259 char fname[PATH_MAX];
260 struct stat sb;
261 int error;
262 int mode; /* open mode */
263 int attr; /* attributes of created file */
264 int action; /* what to do about file */
265 u_char *p, *e;
266 int i;
267 int omode; /* mode to say we opened in */
268 int status;
269 int fd;
271 error = translate_filename(sda->filename1, fname, &r_drive);
272 if (error)
273 return(error);
276 ** get attributes/access mode off stack : low byte is attribute, high
277 ** byte is (sometimes) used in conjunction with 'action'
279 attr = *(u_short *)MAKEPTR(R_SS, R_SP) & 0xff;
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);
298 omode = sda->open_mode & 0x7f;
299 debug(D_REDIR,"open");
300 break;
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");
313 break;
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);
331 omode = sda->ext_mode & 0x7f;
332 debug(D_REDIR,"mopen");
333 break;
335 default:
336 fatal("called int2f11_open for unknown function %x\n",R_AL);
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);
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 */
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);
360 status = 0x03; /* we're going to truncate it */
361 } else {
362 status = 0x01; /* just open it */
364 } else {
365 return(FILE_ALREADY_EXISTS); /* exists, fail */
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);
374 if (R_AL == 0x2e) /* extended wants status returned */
375 R_CX = status;
377 /* black magic to populate the SFT */
379 e = p = sda->filename1 + 2; /* parse name */
380 while (*p) {
381 if (*p++ == '\\') /* look for beginning of filename */
382 e = p;
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] = ' ';
392 if (*e == '.') /* skip period on short names */
393 ++e;
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] = ' ';
402 if (ustat(fname, &sb) < 0) /* re-stat to be accurate */
403 return(WRITE_FAULT); /* any better ideas?! */
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);
420 ** 2f:11:19 2f:11:1b
422 ** find first
424 static int
425 int2f11_findfirst(regcontext_t *REGS __unused)
427 return(find_first(sda->filename1,sda->attrmask,
428 (dosdir_t *)sda->foundentry,
429 (find_block_t *)sda->findfirst));
433 ** 2f:11:1c
435 ** find next
437 static int
438 int2f11_findnext(regcontext_t *REGS __unused)
440 return(find_next((dosdir_t *)sda->foundentry,
441 (find_block_t *)sda->findfirst));
445 ** 2f:11:21
447 ** lseek
449 static int
450 int2f11_lseek(regcontext_t *REGS)
452 int fd;
453 off_t offset;
455 fd = r_sft->fd;
456 offset = (off_t) ((int) ((R_CX << 16) + R_DX));
458 debug(D_REDIR,"lseek(%d, 0x%qx, SEEK_END)\n", fd, offset);
460 if ((offset = lseek(fd, offset, SEEK_END)) < 0) {
461 if (errno == EBADF)
462 return(HANDLE_INVALID);
463 else
464 return(SEEK_ERROR);
466 r_sft->offset = offset; /* update offset in SFT */
467 R_DX = offset >> 16;
468 R_AX = offset;
469 return(0);
473 ** 2f:11:23
475 ** qualify filename
477 static int
478 int2f11_fnqual(regcontext_t *REGS)
480 char *fname;
481 char *tname;
482 static char errmsg[] = "(failed)";
483 int savedrive;
484 int error;
486 return(PATH_NOT_FOUND);
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);
493 error = dos_makepath(fname, tname);
494 if (error)
495 tname = errmsg;
497 diskdrive = savedrive; /* restore correct drive */
499 debug(D_REDIR, "qualify '%s' -> '%s'\n", fname, tname);
500 return(error);
504 ** 2f:11:??
506 ** Null function - we know about it but do nothing
508 static int
509 int2f11_NULLFUNC(regcontext_t *REGS __unused)
511 return(0);
515 ** 2f:11:??
517 ** no function - not handled here (error)
519 static int
520 int2f11_NOFUNC(regcontext_t *REGS __unused)
522 return(-1);
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}
563 static int int2f11_fastlookup[256];
565 /******************************************************************************
566 ** 2f:11
568 ** The DOS redirector interface.
572 ** Verify that the drive being referenced is one we are handling, and
573 ** establish some state for upcoming functions.
575 ** Returns 1 if we should handle this request.
577 ** XXX this is rather inefficient, but much easier to read than the previous
578 ** incarnation 8(
580 static int
581 int2f11_validate(regcontext_t *REGS)
583 int func = R_AL;
584 const char *path = NULL;
585 int doit = 0;
587 /* defaults may help trap problems */
588 r_cds = NULL;
589 r_sft = NULL;
590 r_drive = -1;
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);
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;
616 case 0x0c: /* in es:di */
617 case 0x1c:
618 r_cds = (CDS *)MAKEPTR(R_ES, R_DI);
619 break;
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;
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;
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;
673 if (path) { /* we have a path and need to determine the drive it refers to */
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);
680 /* translate letter to drive number */
681 r_drive = drlton(path[0]);
682 } else {
683 path = "(no path)";
686 /* do we handle this drive? */
687 if (dos_getcwd(r_drive)) {
688 n_drive = r_drive; /* XXX GROSTIC HACK ALERT */
689 doit = 1;
692 debug(D_REDIR,"%s -> drive %c func %x (%sus)\n",
693 path, drntol(r_drive), func, doit?"":"not ");
695 /* so do we deal with this one? */
696 return(doit);
700 int
701 int2f_11(regcontext_t *REGS)
703 int idx;
704 int error;
706 if (!sda) { /* not initialised yet */
707 error = FUNC_NUM_IVALID;
708 } else {
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);
715 reset_poll();
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");
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);
741 /******************************************************************************
742 ** intff handler.
744 ** intff is the (secret, proprietary, internal, evil) call to
745 ** initialise the redirector.
747 static void
748 install_drive(int drive, u_char *path)
750 CDS *cds;
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;
759 /* get the CDS for this drive */
760 cds = (CDS *)MAKEPTR(lol->cds_seg, lol->cds_offset);
761 cds += drive;
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;
768 #endif
770 debug(D_REDIR, "Installing %c: as %s\n", drntol(drive), path);
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 */
780 static void
781 init_drives(void)
783 int drive;
784 u_char *path;
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 */
794 void
795 intff(regcontext_t *REGS)
798 if (lol && sda) { /* already been called? */
799 debug(D_REDIR, "redirector duplicate install ignored");
800 return;
802 lol = (LOL *)MAKEPTR(R_BX, R_DX); /* where DOS keeps its goodies */
803 sda = (SDA *)MAKEPTR(R_DI, R_SI);
804 init_drives();
806 /* initialise dispatcher */
807 intfunc_init(int2f11_table, int2f11_fastlookup);