Subversion Repositories SvarDOS

Rev

Rev 1994 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
28 mv_fox 1
/*
190 mateuszvis 2
 * SVARDOS INSTALL PROGRAM
206 mateuszvis 3
 *
190 mateuszvis 4
 * PUBLISHED UNDER THE TERMS OF THE MIT LICENSE
42 mv_fox 5
 *
1624 mateusz.vi 6
 * COPYRIGHT (C) 2016-2024 MATEUSZ VISTE, ALL RIGHTS RESERVED.
94 mv_fox 7
 *
190 mateuszvis 8
 * Permission is hereby granted, free of charge, to any person obtaining a
9
 * copy of this software and associated documentation files (the "Software"),
10
 * to deal in the Software without restriction, including without limitation
11
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12
 * and/or sell copies of the Software, and to permit persons to whom the
13
 * Software is furnished to do so, subject to the following conditions:
94 mv_fox 14
 *
190 mateuszvis 15
 * The above copyright notice and this permission notice shall be included in
16
 * all copies or substantial portions of the Software.
94 mv_fox 17
 *
190 mateuszvis 18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24
 * DEALINGS IN THE SOFTWARE.
94 mv_fox 25
 *
868 mateusz.vi 26
 * http://svardos.org
28 mv_fox 27
 */
28
 
29
#include <dos.h>
30 mv_fox 30
#include <direct.h>  /* mkdir() */
28 mv_fox 31
#include <stdio.h>   /* printf() and friends */
32
#include <stdlib.h>  /* system() */
33
#include <string.h>  /* memcpy() */
34
#include <unistd.h>
42 mv_fox 35
 
1662 mateusz.vi 36
#include "mdr\cout.h"
1661 mateusz.vi 37
#include "mdr\dos.h"
624 mateuszvis 38
#include "svarlang.lib\svarlang.h"
42 mv_fox 39
 
67 mv_fox 40
/* keyboard layouts and locales */
41
#include "keylay.h"
42
#include "keyoff.h"
42 mv_fox 43
 
908 mateusz.vi 44
 
1664 mateusz.vi 45
/* color scheme (preset for color) */
46
static unsigned char COLOR_TITLEBAR  = 0x70;
1671 mateusz.vi 47
static unsigned char COLOR_TITLEVER  = 0x78;
1664 mateusz.vi 48
static unsigned char COLOR_BODY      = 0x17;
1673 mateusz.vi 49
static unsigned char COLOR_BODYWARN  = 0x1F;
1664 mateusz.vi 50
static unsigned char COLOR_SELECT    = 0x70;
51
static unsigned char COLOR_SELECTCUR = 0x1F;
28 mv_fox 52
 
1671 mateusz.vi 53
/* build release string, populated at startup by reading floppy's label */
54
static char BUILDSTRING[13];
28 mv_fox 55
 
190 mateuszvis 56
/* how much disk space does SvarDOS require (in MiB) */
1928 mateusz.vi 57
#define SVARDOS_DISK_REQ 4
28 mv_fox 58
 
73 mv_fox 59
/* menu screens can output only one of these: */
60
#define MENUNEXT 0
61
#define MENUPREV -1
62
#define MENUQUIT -2
63
 
67 mv_fox 64
/* a convenience 'function' used for debugging */
65
#define DBG(x) { video_putstringfix(24, 0, 0x4F00u, x, 80); }
47 mv_fox 66
 
67 mv_fox 67
struct slocales {
68
  char lang[4];
624 mateuszvis 69
  const char *keybcode;
1908 mateusz.vi 70
  unsigned short codepage;
71
  unsigned char egafile;
72
  unsigned char keybfile;
73
  short keyboff;
74
  short keyblen;
75
  unsigned short keybid;
76
  unsigned short countryid; /* 1=USA, 33=FR, 48=PL, etc */
67 mv_fox 77
};
78
 
79
 
1918 mateusz.vi 80
/* install a dummy int24h handler that always fails. this is to avoid the
81
 * annoying "abort, retry, fail... DOS messages. */
82
static void install_int24(void) {
83
  static unsigned char handler[] = { /* contains machine code instructions */
84
    0xB0, 0x03,  /* mov al, 3   ; tell DOS the action has to FAIL   */
85
    0xCF};       /* ret         ; return from the interrupt handler */
86
  /* install the handler */
87
  _asm {
88
    push dx
89
    mov ax, 0x2524          /* set INT vector 0x24 (to DS:DX)   */
90
    mov dx, offset handler  /* DS:DX points at my dummy handler */
91
    int 0x21
92
    pop dx
93
  }
94
}
95
 
96
 
97
static void exec(const char *s) {
98
  system(s);
99
  install_int24(); /* reinstall my int24 handler, apparently system() reverts
100
                      the original (DOS) one */
101
}
102
 
103
 
1908 mateusz.vi 104
/* put a string on screen and fill it until w chars with white space */
1662 mateusz.vi 105
static void video_putstringfix(unsigned char y, unsigned char x, unsigned char attr, const char *s, unsigned char w) {
106
  unsigned char i;
107
 
108
  /* print the string up to w characters */
109
  i = mdr_cout_str(y, x, s, attr, w);
110
 
111
  /* fill in left space (if any) with blanks */
112
  mdr_cout_char_rep(y, x + i, ' ', attr, w - i);
113
}
114
 
115
 
28 mv_fox 116
/* reboot the computer */
117
static void reboot(void) {
118
  void ((far *bootroutine)()) = (void (far *)()) 0xFFFF0000L;
119
  int far *rstaddr = (int far *)0x00400072L; /* BIOS boot flag is at 0040:0072 */
120
  *rstaddr = 0x1234; /* 0x1234 = warm boot, 0 = cold boot */
121
  (*bootroutine)(); /* jump to the BIOS reboot routine at FFFF:0000 */
122
}
123
 
42 mv_fox 124
 
1669 mateusz.vi 125
/* returns 1 if file exists, zero otherwise */
126
static int fileexists(const char *fname) {
127
  FILE *fd;
128
  fd = fopen(fname, "rb");
129
  if (fd == NULL) return(0);
130
  fclose(fd);
131
  return(1);
132
}
133
 
134
 
56 mv_fox 135
/* outputs a string to screen with taking care of word wrapping. returns amount of lines. */
1662 mateusz.vi 136
static unsigned char putstringwrap(unsigned char y, unsigned char x, unsigned char attr, const char *s) {
137
  unsigned char linew, lincount;
138
  linew = 80 - (x << 1);
56 mv_fox 139
 
140
  for (lincount = 1; y+lincount < 25; lincount++) {
141
    int i, len = linew;
142
    for (i = 0; i <= linew; i++) {
143
      if (s[i] == ' ') len = i;
144
      if (s[i] == '\n') {
145
        len = i;
146
        break;
147
      }
148
      if (s[i] == 0) {
149
        len = i;
150
        break;
151
      }
152
    }
1662 mateusz.vi 153
    mdr_cout_str(y++, x, s, attr, len);
56 mv_fox 154
    s += len;
155
    if (*s == 0) break;
156
    s += 1; /* skip the whitespace char */
157
  }
158
  return(lincount);
159
}
160
 
161
 
162
/* an NLS wrapper around video_putstring(), also performs line wrapping when
163
 * needed. returns the amount of lines that were output */
1662 mateusz.vi 164
static unsigned char putstringnls(unsigned char y, unsigned char x, unsigned char attr, unsigned char nlsmaj, unsigned char nlsmin) {
624 mateuszvis 165
  const char *s = svarlang_str(nlsmaj, nlsmin);
166
  if (s == NULL) s = "";
56 mv_fox 167
  return(putstringwrap(y, x, attr, s));
42 mv_fox 168
}
169
 
170
 
280 mateuszvis 171
/* copy file f1 to f2 using buff as a buffer of buffsz bytes. f2 will be overwritten if it
172
 * exists already! returns 0 on success. */
173
static int fcopy(const char *f2, const char *f1, void *buff, size_t buffsz) {
174
  FILE *fd1, *fd2;
175
  size_t sz;
176
  int res = -1; /* assume failure */
177
 
178
  /* open files */
179
  fd1 = fopen(f1, "rb");
180
  fd2 = fopen(f2, "wb");
181
  if ((fd1 == NULL) || (fd2 == NULL)) goto QUIT;
182
 
183
  /* copy data */
184
  for (;;) {
185
    sz = fread(buff, 1, buffsz, fd1);
186
    if (sz == 0) {
187
      if (feof(fd1) != 0) break;
188
      goto QUIT;
189
    }
190
    if (fwrite(buff, 1, sz, fd2) != sz) goto QUIT;
191
  }
192
 
193
  res = 0; /* success */
194
 
195
  QUIT:
196
  if (fd1 != NULL) fclose(fd1);
197
  if (fd2 != NULL) fclose(fd2);
198
  return(res);
199
}
200
 
201
 
1666 mateusz.vi 202
/* display a menu with items and return user's choice.
203
 * ypos: starting line where the menu is drawn
1948 mateusz.vi 204
 * height: max number of items to display inside the menu
1666 mateusz.vi 205
 * list: NULL-terminated list of items
206
 * maxlistlen: limit list to this many items tops */
1665 mateusz.vi 207
static int menuselect(unsigned char ypos, unsigned char height, const char **list, int maxlistlen) {
208
  int i, offset = 0, res = 0, count;
209
  unsigned char y, xpos, width = 0;
1662 mateusz.vi 210
 
1666 mateusz.vi 211
  /* count how many positions there are, and check their width */
1665 mateusz.vi 212
  for (count = 0; (list[count] != NULL) && (count != maxlistlen); count++) {
28 mv_fox 213
    int len = strlen(list[count]);
214
    if (len > width) width = len;
215
  }
1666 mateusz.vi 216
  width++; /* it's nice to have a small margin to the right of the widest item */
28 mv_fox 217
 
1948 mateusz.vi 218
  /* adjust height if there is less items than max height */
219
  if (count < height) height = count;
220
 
28 mv_fox 221
  /* if xpos negative, means 'center out' */
1665 mateusz.vi 222
  xpos = 39 - (width >> 1);
28 mv_fox 223
 
1666 mateusz.vi 224
  mdr_cout_char_rep(ypos, xpos, 0xC4, COLOR_SELECT, width + 2);  /* top line */
1664 mateusz.vi 225
  mdr_cout_char(ypos, xpos+width+2, 0xBF, COLOR_SELECT);         /*       \ */
226
  mdr_cout_char(ypos, xpos-1, 0xDA, COLOR_SELECT);               /*  /      */
1666 mateusz.vi 227
  ypos++; /* from now on ypos relates to the position of the content */
228
  mdr_cout_char(ypos+height, xpos-1, 0xC0, COLOR_SELECT);      /*  \      */
229
  mdr_cout_char(ypos+height, xpos+width+2, 0xD9, COLOR_SELECT);/*      /  */
230
  mdr_cout_char_rep(ypos+height, xpos, 0xC4, COLOR_SELECT, width + 2);
28 mv_fox 231
 
232
  for (;;) {
233
    int key;
1666 mateusz.vi 234
 
235
    /* draw side borders of the menu + the cursor */
236
    if (count <= height) { /* no need for a cursor, all fits on one page */
237
      i = 255;
238
    } else {
239
      i = offset * (height - 1) / (count - height);
240
    }
241
 
242
    for (y = ypos; y < (ypos + height); y++) {
243
      mdr_cout_char(y, xpos-1, 0xB3, COLOR_SELECT); /* left side */
244
      if (y - ypos == i) {
1667 mateusz.vi 245
        mdr_cout_char(y, xpos+width+2, '=', COLOR_SELECT); /* cursor */
1666 mateusz.vi 246
      } else {
247
        mdr_cout_char(y, xpos+width+2, 0xB3, COLOR_SELECT); /* right side */
248
      }
249
    }
250
 
28 mv_fox 251
    /* list of selectable items */
1666 mateusz.vi 252
    for (i = 0; i < height; i++) {
28 mv_fox 253
      if (i + offset == res) {
1666 mateusz.vi 254
        mdr_cout_char(ypos + i, xpos, 16, COLOR_SELECTCUR);
255
        mdr_cout_char(ypos + i, xpos+width+1, 17, COLOR_SELECTCUR);
256
        mdr_cout_locate(ypos + i, xpos);
257
        video_putstringfix(ypos + i, xpos+1, COLOR_SELECTCUR, list[i + offset], width);
28 mv_fox 258
      } else if (i + offset < count) {
1666 mateusz.vi 259
        mdr_cout_char(ypos + i, xpos, ' ', COLOR_SELECT);
260
        mdr_cout_char(ypos + i, xpos+width+1, ' ', COLOR_SELECT);
261
        video_putstringfix(ypos + i, xpos+1, COLOR_SELECT, list[i + offset], width);
28 mv_fox 262
      } else {
1666 mateusz.vi 263
        mdr_cout_char_rep(ypos + i, xpos, ' ', COLOR_SELECT, width+2);
28 mv_fox 264
      }
265
    }
1661 mateusz.vi 266
    key = mdr_dos_getkey();
28 mv_fox 267
    if (key == 0x0D) { /* ENTER */
268
      return(res);
269
    } else if (key == 0x148) { /* up */
1948 mateusz.vi 270
      UP_AGAIN:
33 mv_fox 271
      if (res > 0) {
272
        res--;
273
        if (res < offset) offset = res;
1948 mateusz.vi 274
        if (list[res][0] == 0) goto UP_AGAIN;
33 mv_fox 275
      }
28 mv_fox 276
    } else if (key == 0x150) { /* down */
1948 mateusz.vi 277
      DOWN_AGAIN:
33 mv_fox 278
      if (res+1 < count) {
279
        res++;
1666 mateusz.vi 280
        if (res > offset + height - 1) offset = res - (height - 1);
1948 mateusz.vi 281
        if (list[res][0] == 0) goto DOWN_AGAIN;
33 mv_fox 282
      }
283
    } else if (key == 0x147) { /* home */
284
      res = 0;
285
      offset = 0;
286
    } else if (key == 0x14F) { /* end */
287
      res = count - 1;
1666 mateusz.vi 288
      if (res > offset + height - 1) offset = res - (height - 1);
28 mv_fox 289
    } else if (key == 0x1B) {  /* ESC */
290
      return(-1);
78 mv_fox 291
    }/* else {
33 mv_fox 292
      char buf[8];
55 mv_fox 293
      snprintf(buf, sizeof(buf), "0x%02X ", key);
1664 mateusz.vi 294
      video_putstring(1, 0, COLOR_BODY, buf, -1);
78 mv_fox 295
    }*/
28 mv_fox 296
  }
297
}
298
 
1946 mateusz.vi 299
 
1662 mateusz.vi 300
static void newscreen(unsigned char statusbartype) {
624 mateuszvis 301
  const char *msg;
1664 mateusz.vi 302
  mdr_cout_cls(COLOR_BODY);
624 mateuszvis 303
  msg = svarlang_strid(0x00); /* "SVARDOS INSTALLATION" */
1664 mateusz.vi 304
  mdr_cout_char_rep(0, 0, ' ', COLOR_TITLEBAR, 80);
305
  mdr_cout_str(0, 40 - (strlen(msg) >> 1), msg, COLOR_TITLEBAR, 80);
1671 mateusz.vi 306
  mdr_cout_str(0, 80 - strlen(BUILDSTRING), BUILDSTRING, COLOR_TITLEVER, 12);
307
 
79 mv_fox 308
  switch (statusbartype) {
309
    case 1:
624 mateuszvis 310
      msg = svarlang_strid(0x000B); /* "Up/Down = Select entry | Enter = Validate your choice | ESC = Quit to DOS" */
79 mv_fox 311
      break;
312
    case 2:
624 mateuszvis 313
      msg = svarlang_strid(0x0005); /* "Press any key..." */
79 mv_fox 314
      break;
315
    case 3:
316
      msg = "";
317
      break;
318
    default:
624 mateuszvis 319
      msg = svarlang_strid(0x000A); /* "Up/Down = Select entry | Enter = Validate your choice | ESC = Previous screen" */
79 mv_fox 320
      break;
321
  }
1664 mateusz.vi 322
  mdr_cout_char(24, 0, ' ', COLOR_TITLEBAR);
323
  video_putstringfix(24, 1, COLOR_TITLEBAR, msg, 79);
1662 mateusz.vi 324
  mdr_cout_locate(25,0);
28 mv_fox 325
}
326
 
1908 mateusz.vi 327
 
96 mv_fox 328
/* fills a slocales struct accordingly to the value of its keyboff member */
329
static void kblay2slocal(struct slocales *locales) {
624 mateuszvis 330
  const char *m;
96 mv_fox 331
  for (m = kblayouts[locales->keyboff]; *m != 0; m++); /* skip layout name */
332
  m++;
333
  /* skip keyb code and copy it to locales.keybcode */
334
  locales->keybcode = m;
335
  for (; *m != 0; m++);
336
  /* */
337
  locales->codepage = ((unsigned short)m[1] << 8) | m[2];
338
  locales->egafile = m[3];
339
  locales->keybfile = m[4];
340
  locales->keybid = ((unsigned short)m[5] << 8) | m[6];
1908 mateusz.vi 341
  locales->countryid = ((unsigned short)m[7] << 8) | m[8];
96 mv_fox 342
}
343
 
1908 mateusz.vi 344
 
67 mv_fox 345
static int selectlang(struct slocales *locales) {
346
  int choice, x;
624 mateuszvis 347
  const char *msg;
348
  const char *langlist[] = {
67 mv_fox 349
    "English",
1177 mateusz.vi 350
    "Brazilian",
67 mv_fox 351
    "French",
133 mv_fox 352
    "German",
119 mv_fox 353
    "Italian",
67 mv_fox 354
    "Polish",
116 mv_fox 355
    "Russian",
123 mv_fox 356
    "Slovene",
128 mv_fox 357
    "Swedish",
67 mv_fox 358
    "Turkish",
28 mv_fox 359
    NULL
360
  };
361
 
79 mv_fox 362
  newscreen(1);
624 mateuszvis 363
  msg = svarlang_strid(0x0100); /* "Welcome to SvarDOS" */
42 mv_fox 364
  x = 40 - (strlen(msg) >> 1);
1664 mateusz.vi 365
  mdr_cout_str(4, x, msg, COLOR_BODY, 80);
366
  mdr_cout_char_rep(5, x, '=', COLOR_BODY, strlen(msg));
1662 mateusz.vi 367
 
368
  /* center out the string "Please select your language..." */
369
  msg = svarlang_str(1, 1); /* "Please select your language from the list below:" */
370
  if (strlen(msg) > 74) {
1664 mateusz.vi 371
    putstringwrap(8, 1, COLOR_BODY, msg);
1662 mateusz.vi 372
  } else {
1664 mateusz.vi 373
    mdr_cout_str(8, 40 - (strlen(msg) / 2), msg, COLOR_BODY, 80);
1662 mateusz.vi 374
  }
375
 
1666 mateusz.vi 376
  choice = menuselect(11, 9, langlist, -1);
73 mv_fox 377
  if (choice < 0) return(MENUPREV);
1669 mateusz.vi 378
 
67 mv_fox 379
  /* populate locales with default values */
380
  memset(locales, 0, sizeof(struct slocales));
381
  switch (choice) {
382
    case 1:
1179 mateusz.vi 383
      strcpy(locales->lang, "BR");
384
      locales->keyboff = OFFLOC_BR;
385
      locales->keyblen = OFFLEN_BR;
386
      break;
387
    case 2:
67 mv_fox 388
      strcpy(locales->lang, "FR");
389
      locales->keyboff = OFFLOC_FR;
390
      locales->keyblen = OFFLEN_FR;
391
      break;
1177 mateusz.vi 392
    case 3:
133 mv_fox 393
      strcpy(locales->lang, "DE");
394
      locales->keyboff = OFFLOC_DE;
395
      locales->keyblen = OFFLEN_DE;
396
      break;
1177 mateusz.vi 397
    case 4:
119 mv_fox 398
      strcpy(locales->lang, "IT");
399
      locales->keyboff = OFFLOC_IT;
400
      locales->keyblen = OFFLEN_IT;
401
      break;
1177 mateusz.vi 402
    case 5:
67 mv_fox 403
      strcpy(locales->lang, "PL");
404
      locales->keyboff = OFFLOC_PL;
405
      locales->keyblen = OFFLEN_PL;
406
      break;
1177 mateusz.vi 407
    case 6:
116 mv_fox 408
      strcpy(locales->lang, "RU");
409
      locales->keyboff = OFFLOC_RU;
410
      locales->keyblen = OFFLEN_RU;
411
      break;
1177 mateusz.vi 412
    case 7:
123 mv_fox 413
      strcpy(locales->lang, "SI");
414
      locales->keyboff = OFFLOC_SI;
415
      locales->keyblen = OFFLEN_SI;
416
      break;
1177 mateusz.vi 417
    case 8:
128 mv_fox 418
      strcpy(locales->lang, "SV");
419
      locales->keyboff = OFFLOC_SV;
420
      locales->keyblen = OFFLEN_SV;
421
      break;
1177 mateusz.vi 422
    case 9:
67 mv_fox 423
      strcpy(locales->lang, "TR");
424
      locales->keyboff = OFFLOC_TR;
425
      locales->keyblen = OFFLEN_TR;
426
      break;
427
    default:
428
      strcpy(locales->lang, "EN");
429
      locales->keyboff = 0;
430
      locales->keyblen = OFFCOUNT;
431
      break;
432
  }
96 mv_fox 433
  /* populate the slocales struct accordingly to the keyboff member */
434
  kblay2slocal(locales);
67 mv_fox 435
  /* */
73 mv_fox 436
  return(MENUNEXT);
28 mv_fox 437
}
438
 
439
 
67 mv_fox 440
static int selectkeyb(struct slocales *locales) {
96 mv_fox 441
  int menuheight, choice;
442
  if (locales->keyblen == 1) return(MENUNEXT); /* do not ask for keyboard layout if only one is available for given language */
79 mv_fox 443
  newscreen(0);
1664 mateusz.vi 444
  putstringnls(5, 1, COLOR_BODY, 1, 5); /* "SvarDOS supports different keyboard layouts */
1666 mateusz.vi 445
  menuheight = locales->keyblen;
446
  if (menuheight > 11) menuheight = 11;
1665 mateusz.vi 447
  choice = menuselect(10, menuheight, &(kblayouts[locales->keyboff]), locales->keyblen);
96 mv_fox 448
  if (choice < 0) return(MENUPREV);
449
  /* (re)load the keyboard layout & codepage setup */
450
  locales->keyboff += choice;
451
  kblay2slocal(locales);
73 mv_fox 452
  return(MENUNEXT);
67 mv_fox 453
}
454
 
455
 
28 mv_fox 456
/* returns 0 if installation must proceed, non-zero otherwise */
457
static int welcomescreen(void) {
73 mv_fox 458
  int c;
624 mateuszvis 459
  const char *choice[3];
460
  choice[0] = svarlang_strid(0x0001);
461
  choice[1] = svarlang_strid(0x0002);
462
  choice[2] = NULL;
79 mv_fox 463
  newscreen(0);
1664 mateusz.vi 464
  putstringnls(4, 1, COLOR_BODY, 2, 0); /* "You are about to install SvarDOS */
1666 mateusz.vi 465
  c = menuselect(13, 2, choice, -1);
73 mv_fox 466
  if (c < 0) return(MENUPREV);
467
  if (c == 0) return(MENUNEXT);
468
  return(MENUQUIT);
28 mv_fox 469
}
470
 
471
 
1908 mateusz.vi 472
/* returns total disk space of drive drv (in MiB, max 2048, A=1 B=2 etc), or -1 if drive invalid */
1911 mateusz.vi 473
static int disksize(unsigned char drv) {
474
  unsigned short sec_per_cluster = 0;
475
  unsigned short tot_clusters = 0;
476
  unsigned short bytes_per_sec = 0;
477
  long res;
478
  _asm {
479
    push ax
480
    push bx
481
    push cx
482
    push dx
35 mv_fox 483
 
1911 mateusz.vi 484
    mov ah, 0x36
485
    mov dl, drv
486
    int 0x21
487
    /* AX=sec_per_cluster DX=tot_clusters BX=free_clusters CX=bytes_per_sec */
488
    mov sec_per_cluster, ax
489
    mov bytes_per_sec, cx
490
    mov tot_clusters, dx
35 mv_fox 491
 
1911 mateusz.vi 492
    pop dx
493
    pop cx
494
    pop bx
495
    pop ax
496
  }
497
 
498
  if (sec_per_cluster == 0xffff) return(-1);
499
  res = sec_per_cluster;
500
  res *= tot_clusters;
501
  res *= bytes_per_sec;
502
  res >>= 20;
503
  return((int)res);
504
}
505
 
506
 
35 mv_fox 507
/* returns 0 if disk is empty, non-zero otherwise */
1942 mateusz.vi 508
static int diskempty(char drv) {
35 mv_fox 509
  unsigned int rc;
510
  int res;
511
  char buff[8];
512
  struct find_t fileinfo;
1942 mateusz.vi 513
  snprintf(buff, sizeof(buff), "%c:\\*.*", drv);
35 mv_fox 514
  rc = _dos_findfirst(buff, _A_NORMAL | _A_SUBDIR | _A_HIDDEN | _A_SYSTEM, &fileinfo);
515
  if (rc == 0) {
516
    res = 1; /* call successfull means disk is not empty */
28 mv_fox 517
  } else {
35 mv_fox 518
    res = 0;
28 mv_fox 519
  }
35 mv_fox 520
  /* _dos_findclose(&fileinfo); */ /* apparently required only on OS/2 */
28 mv_fox 521
  return(res);
522
}
523
 
200 mateuszvis 524
 
1930 mateusz.vi 525
/* replace all occurences of char a by char b in s */
526
static void strtr(char *s, char a, char b) {
527
  for (;*s != 0; s++) {
528
    if (*s == a) *s = b;
529
  }
530
}
531
 
532
 
898 mateusz.vi 533
/* tries to write an empty file to drive.
534
 * asks DOS to inhibit the int 24h handler for this job, so erros are
535
 * gracefully reported - unfortunately this does not work under FreeDOS because
536
 * the DOS-C kernel does not implement the required flag.
537
 * returns 0 on success (ie. "disk exists and is writeable"). */
1908 mateusz.vi 538
static unsigned short test_drive_write(char drive) {
898 mateusz.vi 539
  unsigned short result = 0;
1908 mateusz.vi 540
  char *buff = "@:\\SVWRTEST.123";
541
  buff[0] = drive;
898 mateusz.vi 542
  _asm {
543
    push ax
544
    push bx
545
    push cx
546
    push dx
547
 
548
    mov ah, 0x6c   /* extended open/create file */
549
    mov bx, 0x2001 /* open for write + inhibit int 24h handler */
550
    xor cx, cx     /* file attributes on the created file */
551
    mov dx, 0x0010 /* create file if does not exist, fail if it exists */
552
    mov si, buff   /* filename to create */
553
    int 0x21
554
    jc FAILURE
555
    /* close the file (handle in AX) */
556
    mov bx, ax
557
    mov ah, 0x3e /* close file */
558
    int 0x21
559
    jc FAILURE
560
    /* delete the file */
561
    mov ah, 0x41 /* delete file pointed out by DS:DX */
562
    mov dx, buff
563
    int 0x21
564
    jnc DONE
565
 
566
    FAILURE:
567
    mov result, ax
568
    DONE:
569
 
570
    pop dx
571
    pop cx
572
    pop bx
573
    pop ax
574
  }
575
  return(result);
576
}
577
 
578
 
1944 mateusz.vi 579
#define MBR_WRITE 3
580
#define MBR_READ 2
581
/* read (action=2) or write (action=3) MBR of driveid (0x80, 0x81..) into buff */
582
static int READ_OR_WRITE_MBR(unsigned char action, char *buff, unsigned char driveid);
583
#pragma aux READ_OR_WRITE_MBR = \
1939 mateusz.vi 584
"push es" \
1944 mateusz.vi 585
"mov al, 1"       /* read 1 sector into memory */ \
1940 mateusz.vi 586
"mov cx, 0x0001"  /* cylinder 0, sector 1 */ \
587
"xor dh, dh"      /* head 0 */ \
1939 mateusz.vi 588
"push ds" \
589
"pop es" \
590
"int 0x13" \
591
"mov ax, 0" /* do not do "xor ax, ax", CF needs to be preserved */ \
592
"jnc DONE" \
593
"inc ax" \
594
"DONE:" \
595
"pop es" \
1944 mateusz.vi 596
parm [ah] [bx] [dl] \
1940 mateusz.vi 597
modify [cx dx] \
1939 mateusz.vi 598
value [ax]
599
 
600
 
1944 mateusz.vi 601
 
1939 mateusz.vi 602
/*
603
 * MBR structure:
604
 *
605
 * Boot signature (word 0xAA55) is at 0x01FE
606
 *
607
 * partition entry 1 is at 0x01BE
608
 *                 2    at 0x01CE
609
 *                 3    at 0x01DE
610
 *                 4    at 0x01EE
611
 *
612
 * a partition entry is:
613
 * 0x00  status byte (active is bit 0x80 set)
614
 * 0x01  CHS addr of first sector (here: HEAD)
615
 * 0x02  CHS addr of first sector (CCSSSSSS) sector in 6 low bits, cylinder high bits in CC
616
 * 0x03  CHS addr of furst sector (here: low 8 bits of cylinder)
617
 * 0x04  Partition type:
618
        0x06/0x08 for CHS FAT16/32
619
        0x0E/0x0C for LBA FAT16/32
620
 * 0x05  CHS addr of last sector (same format as for 1st sector)
621
 * 0x06  CHS addr of last sector (same format as for 1st sector)
622
 * 0x07  CHS addr of last sector (same format as for 1st sector)
623
 * 0x08  LBA addr of first sector (4 bytes) - used sometimes instead of CHS
624
 * 0x0C  number of sectors in partition (4 bytes)
625
 */
626
 
627
struct drivelist {
1940 mateusz.vi 628
  unsigned long start_lba;
1943 mateusz.vi 629
  unsigned long tot_sect;  /* size (of partition), in sectors */
1940 mateusz.vi 630
  unsigned short tot_size; /* size in MiB */
1943 mateusz.vi 631
  unsigned char partid;    /* position of the partition in the MBR (0,1,2,3) */
1944 mateusz.vi 632
  unsigned char hd;        /* 0-3 */
633
  unsigned char dosid;     /* DOS drive id (A=0, B=1...)*/
1939 mateusz.vi 634
};
635
 
1940 mateusz.vi 636
 
637
/* a (very partial) struct mimicking what EDR-DOS uses in int 2Fh,AX=0803h */
638
#pragma pack (push)
639
#pragma pack (0) /* disable the automatic alignment of struct members */
640
struct dos_udsc {
1944 mateusz.vi 641
  unsigned short next_off; /* offset FFFFh if last */
1940 mateusz.vi 642
  unsigned short next_seg;
1944 mateusz.vi 643
  unsigned char hd;        /* physical unit (as in int 13h) */
644
  unsigned char letter;    /* DOS letter drive (A=0, B=1, C=2, ...) */
1940 mateusz.vi 645
  unsigned short sectsize; /* bytes per sector */
646
  unsigned char unknown[15];
647
  unsigned long start_lba; /* LBA address of the partition (only for primary partitions) */
648
};
649
#pragma pack (pop)
650
 
651
 
652
/* get the DOS drive data table list */
653
static struct dos_udsc far *get_dos_udsc(void)  {
654
  unsigned short udsc_seg = 0, udsc_off = 0;
655
  _asm {
656
    push ds
657
    push di
658
 
659
    mov ax, 0x0803
660
    int 0x2f
661
    /* drive data table list is in DS:DI now */
662
    mov udsc_seg, ds
663
    mov udsc_off, di
664
 
665
    pop di
666
    pop ds
667
  }
668
  if (udsc_off == 0xffff) return(NULL);
669
  return(MK_FP(udsc_seg, udsc_off));
670
}
671
 
672
 
1994 mateusz.vi 673
/* returns 0 if fsid is a valid (recognized) filesystem for SvarDOS install  */
1996 mateusz.vi 674
static int is_fstype_valid(unsigned char fsid) {
1994 mateusz.vi 675
  switch (fsid) {
676
    case 0x01: /* FAT-12 in first 32M of disk                                */
677
    case 0x04: /* FAT-16 partition that resides within first 32M of disk     */
678
    case 0x06: /* FAT-16B with 64K+ sectors, must be within first 8G of disk */
679
    case 0x0B: /* FAT-32 with CHS addressing                                 */
680
    case 0x0C: /* FAT-32 with LBA addressing                                 */
681
    case 0x0E: /* FAT-16B with LBA addressing                                */
682
      return(0);
683
    default:
684
      return(-1);
685
  }
686
}
687
 
688
 
1940 mateusz.vi 689
/* reads the MBR and matches its entries to DOS drives
1943 mateusz.vi 690
 * fills the drives array with up to 16 drives (4 partitions * 4 disks)
1940 mateusz.vi 691
 * see https://github.com/SvarDOS/bugz/issues/89 */
1943 mateusz.vi 692
static int get_drives_list(char *buff, struct drivelist *drives) {
1939 mateusz.vi 693
  int i;
1943 mateusz.vi 694
  int listlen = 0;
695
  int drv;
1940 mateusz.vi 696
  struct dos_udsc far *udsc_root = get_dos_udsc();
697
  struct dos_udsc far *udsc_node;
1939 mateusz.vi 698
 
1943 mateusz.vi 699
  for (drv = 0x80; drv < 0x84; drv++) {
1940 mateusz.vi 700
 
1944 mateusz.vi 701
    if (READ_OR_WRITE_MBR(MBR_READ, buff, drv) != 0) continue;
1939 mateusz.vi 702
 
1943 mateusz.vi 703
    /* check boot signature at 0x01fe */
704
    if (*(unsigned short *)(buff + 0x01fe) != 0xAA55) continue;
1939 mateusz.vi 705
 
1943 mateusz.vi 706
    /* iterate over the 4 partitions in the MBR */
707
    for (i = 0; i < 4; i++) {
708
      unsigned char *entry;
1939 mateusz.vi 709
 
1943 mateusz.vi 710
      entry = buff + 0x01BE + (i * 16);
1939 mateusz.vi 711
 
1943 mateusz.vi 712
      /* ignore partition if fs is unknown (non-FAT) */
1994 mateusz.vi 713
      if (is_fstype_valid(entry[4]) != 0) continue;
714
 
1943 mateusz.vi 715
      bzero(&(drives[listlen]), sizeof(struct drivelist));
1944 mateusz.vi 716
      drives[listlen].hd = drv & 3;
1943 mateusz.vi 717
      drives[listlen].partid = i;
718
      drives[listlen].start_lba = ((unsigned long *)entry)[2];
719
      drives[listlen].tot_sect = ((unsigned long *)entry)[3];
1939 mateusz.vi 720
 
1943 mateusz.vi 721
      /* now iterate over DOS drives and try to match ont to this MBR entry */
722
      udsc_node = udsc_root;
723
      while (udsc_node != NULL) {
724
        if (udsc_node->hd != drv) goto NEXT;
725
        if (udsc_node->start_lba != drives[listlen].start_lba) goto NEXT;
1939 mateusz.vi 726
 
1943 mateusz.vi 727
        /* FOUND! */
1944 mateusz.vi 728
        drives[listlen].dosid = udsc_node->letter;
1943 mateusz.vi 729
        {
730
          unsigned long sz = (drives[listlen].tot_sect * udsc_node->sectsize) >> 20;
731
          drives[listlen].tot_size = (unsigned short)sz;
732
        }
733
        listlen++;
734
        break;
735
 
736
        NEXT:
737
        if (udsc_node->next_off == 0xffff) break;
738
        udsc_node = MK_FP(udsc_node->next_seg, udsc_node->next_off);
739
      } /* iterate over UDSC nodes */
740
    } /* iterate over partition entries of the MBR */
741
  } /* iterate over BIOS disks (0x80, 0x81, ...) */
742
 
743
  return(listlen);
1939 mateusz.vi 744
}
745
 
746
 
1942 mateusz.vi 747
/* displays a list of drives and asks user to choose one for installation
1944 mateusz.vi 748
 * returns a word with bits HHPPLLLLLLLL where:
749
 * HH = hard drive id (0..3)
750
 * PP = position of the partition in MBR (0..3)
751
 * LL... = drive's DOS id (A=0, B=1, C=2, ...) */
1942 mateusz.vi 752
static int selectdrive(void) {
1935 mateusz.vi 753
  char buff[512];
1943 mateusz.vi 754
  struct drivelist drives[16];
755
  char drvlist[16][32]; /* up to 16 drives (4 partitions on 4 disks) */
756
  int i, drvlistlen;
1942 mateusz.vi 757
  const char *menulist[16];
758
  unsigned char driveid = 1; /* fdisk runs on first drive (unless USB boot) */
1935 mateusz.vi 759
 
1940 mateusz.vi 760
  /* read MBR of first HDD */
1943 mateusz.vi 761
  drvlistlen = get_drives_list(buff, drives);
1939 mateusz.vi 762
 
1942 mateusz.vi 763
  /* if no drive found - disk not partitioned? */
764
  if (drvlistlen == 0) {
765
    const char *list[4];
766
    newscreen(0);
767
    list[0] = svarlang_str(0, 3); /* Create a partition automatically */
768
    list[1] = svarlang_str(0, 4); /* Run the FDISK tool */
769
    list[2] = svarlang_str(0, 2); /* Quit to DOS */
770
    list[3] = NULL;
771
    snprintf(buff, sizeof(buff), svarlang_strid(0x0300), SVARDOS_DISK_REQ); /* "ERROR: No drive could be found. Note, that SvarDOS requires at least %d MiB of available disk space */
772
    switch (menuselect(6 + putstringwrap(4, 1, COLOR_BODY, buff), 3, list, -1)) {
773
      case 0:
774
        sprintf(buff, "FDISK /PRI:MAX %u", driveid);
775
        exec(buff);
776
        break;
777
      case 1:
778
        mdr_cout_cls(0x07);
779
        mdr_cout_locate(0, 0);
780
        sprintf(buff, "FDISK %u", driveid);
781
        exec(buff);
782
        break;
783
      case 2:
784
        return(MENUQUIT);
785
      default:
786
        return(-1);
1908 mateusz.vi 787
    }
1942 mateusz.vi 788
    /* write a temporary MBR which only skips the drive (in case BIOS would
789
     * try to boot off the not-yet-ready C: disk) */
790
    sprintf(buff, "FDISK /LOADIPL %u", driveid);
791
    exec(buff); /* writes BOOT.MBR into actual MBR */
792
    newscreen(2);
793
    putstringnls(10, 10, COLOR_BODY, 3, 1); /* "Your computer will reboot now." */
794
    putstringnls(12, 10, COLOR_BODY, 0, 5); /* "Press any key..." */
795
    mdr_dos_getkey();
796
    reboot();
797
    return(MENUQUIT);
798
  }
1908 mateusz.vi 799
 
1943 mateusz.vi 800
  /* build a menu with all drives */
801
  for (i = 0; i < drvlistlen; i++) {
1944 mateusz.vi 802
    snprintf(drvlist[i], sizeof(drvlist[0]), "%c: [%u MiB, hd%c%u]", 'A' + drives[i].dosid, drives[i].tot_size, 'a' + drives[i].hd, drives[i].partid);
1943 mateusz.vi 803
    menulist[i] = drvlist[i];
804
  }
1948 mateusz.vi 805
  menulist[i++] = "";
1942 mateusz.vi 806
  menulist[i++] = svarlang_str(0, 2); /* Quit to DOS */
807
  menulist[i] = NULL;
1943 mateusz.vi 808
 
1942 mateusz.vi 809
  newscreen(0);
1948 mateusz.vi 810
 
1949 mateusz.vi 811
  snprintf(buff, sizeof(buff), "%s", svarlang_strid(0x0307));
1948 mateusz.vi 812
  i = menuselect(7 + putstringwrap(4, 1, COLOR_BODY, buff) /*ypos*/, 10 /*max-height*/, menulist, -1);
1942 mateusz.vi 813
  if (i < 0) {
814
    return(MENUPREV);
815
  } else if (i < drvlistlen) {
1944 mateusz.vi 816
    /* return a bitfield HHPPLLLLLLLL
817
     * HH = hard drive id (0..3)
818
     * PP = position of the partition in MBR (0..3)
819
     * LL... = drive's DOS id (A=0, B=1, C=2, ...) */
820
    return((drives[i].partid << 8) | (drives[i].hd << 10) | drives[i].dosid);
1942 mateusz.vi 821
  }
1935 mateusz.vi 822
 
1942 mateusz.vi 823
  return(MENUQUIT);
824
}
1935 mateusz.vi 825
 
1944 mateusz.vi 826
/* hd_drv is a bitfield HHPPLLLLLLLL
827
 * HH = hard drive id (0..3)
828
 * PP = position of the partition in MBR (0..3)
829
 * LL... = drive's DOS id (A=0, B=1, C=2, ...) */
1942 mateusz.vi 830
static int preparedrive(int hd_drv) {
831
  unsigned char selecteddrive;
1944 mateusz.vi 832
  unsigned char driveid, partid;
1942 mateusz.vi 833
  char cselecteddrive;
834
  int choice;
835
  char buff[512];
556 mateuszvis 836
 
1942 mateusz.vi 837
  /* decode hd and drive id from hd_drv */
1944 mateusz.vi 838
  selecteddrive = hd_drv & 0xff; /* DOS drive letter (A=0. B=1, C=2 etc) */
839
  partid = (hd_drv >> 8) & 3;    /* position of partition in MBR (0..3) */
840
  driveid = (hd_drv >> 10);      /* HDD identifier (0..3) */
556 mateuszvis 841
 
1944 mateusz.vi 842
  cselecteddrive = 'A' + selecteddrive;
1935 mateusz.vi 843
 
1942 mateusz.vi 844
  TRY_AGAIN:
1935 mateusz.vi 845
 
1942 mateusz.vi 846
  /* if not formatted, propose to format it right away (try to create a directory) */
847
  if (test_drive_write(cselecteddrive) != 0) {
848
    const char *list[3];
79 mv_fox 849
    newscreen(0);
1942 mateusz.vi 850
    snprintf(buff, sizeof(buff), svarlang_str(3, 3), cselecteddrive); /* "ERROR: Drive %c: seems to be unformated. Do you wish to format it?") */
851
    mdr_cout_str(7, 1, buff, COLOR_BODY, 80);
556 mateuszvis 852
 
1942 mateusz.vi 853
    snprintf(buff, sizeof(buff), svarlang_strid(0x0007), cselecteddrive); /* "Format drive %c:" */
854
    list[0] = buff;
855
    list[1] = svarlang_strid(0x0002); /* "Quit to DOS" */
856
    list[2] = NULL;
556 mateuszvis 857
 
1942 mateusz.vi 858
    choice = menuselect(12, 2, list, -1);
859
    if (choice < 0) return(MENUPREV);
860
    if (choice == 1) return(MENUQUIT);
861
    mdr_cout_cls(0x07);
862
    mdr_cout_locate(0, 0);
863
    snprintf(buff, sizeof(buff), "FORMAT %c: /Q /U /Z:seriously /V:SVARDOS", cselecteddrive);
864
    exec(buff);
865
    goto TRY_AGAIN;
28 mv_fox 866
  }
1942 mateusz.vi 867
 
868
  /* check total disk space */
1944 mateusz.vi 869
  if (disksize(selecteddrive+1) < SVARDOS_DISK_REQ) {
1942 mateusz.vi 870
    int y = 9;
871
    newscreen(2);
872
    snprintf(buff, sizeof(buff), svarlang_strid(0x0304), cselecteddrive, SVARDOS_DISK_REQ); /* "ERROR: Drive %c: is not big enough! SvarDOS requires a disk of at least %d MiB." */
873
    y += putstringwrap(y, 1, COLOR_BODY, buff);
874
    putstringnls(++y, 1, COLOR_BODY, 0, 5); /* "Press any key..." */
875
    mdr_dos_getkey();
876
    return(MENUPREV);
877
  }
878
 
879
  /* is the disk empty? */
880
  newscreen(0);
881
  if (diskempty(cselecteddrive) != 0) {
882
    const char *list[3];
883
    int y = 6;
884
    snprintf(buff, sizeof(buff), svarlang_strid(0x0305), cselecteddrive); /* "ERROR: Drive %c: not empty" */
885
    y += putstringwrap(y, 1, COLOR_BODY, buff);
886
 
887
    snprintf(buff, sizeof(buff), svarlang_strid(0x0007), cselecteddrive); /* "Format drive %c:" */
888
    list[0] = buff;
889
    list[1] = svarlang_strid(0x0002); /* "Quit to DOS" */
890
    list[2] = NULL;
891
 
892
    choice = menuselect(++y, 2, list, -1);
893
    if (choice < 0) return(MENUPREV);
894
    if (choice == 1) return(MENUQUIT);
895
    mdr_cout_cls(0x07);
896
    mdr_cout_locate(0, 0);
897
    snprintf(buff, sizeof(buff), "FORMAT %c: /Q /U /Z:seriously /V:SVARDOS", cselecteddrive);
898
    exec(buff);
899
    goto TRY_AGAIN;
900
  } else {
901
    /* final confirmation */
902
    const char *list[3];
903
    list[0] = svarlang_strid(0x0001); /* Install SvarDOS */
904
    list[1] = svarlang_strid(0x0002); /* Quit to DOS */
905
    list[2] = NULL;
906
    snprintf(buff, sizeof(buff), svarlang_strid(0x0306), cselecteddrive); /* "The installation of SvarDOS to %c: is about to begin." */
907
    mdr_cout_str(7, 40 - (strlen(buff) / 2), buff, COLOR_BODY, 80);
908
    choice = menuselect(10, 2, list, -1);
909
    if (choice < 0) return(MENUPREV);
910
    if (choice == 1) return(MENUQUIT);
1944 mateusz.vi 911
 
912
    /* update the disk's MBR, transfer the boot system, make sure the partition
913
     * is ACTIVE and create a TEMP directory to copy SVP files over */
1942 mateusz.vi 914
    snprintf(buff, sizeof(buff), "SYS %c: > NUL", cselecteddrive);
915
    exec(buff);
1944 mateusz.vi 916
    sprintf(buff, "FDISK /MBR %u", driveid + 1);
1942 mateusz.vi 917
    exec(buff);
1944 mateusz.vi 918
 
919
    if (READ_OR_WRITE_MBR(MBR_READ, buff, driveid | 0x80) == 0) {
920
      /* active flags for part 0,1,2,3 are at offsets 0x01BE, 0x01CE, 0x01DE, 0x01EE */
921
      unsigned char i, flag_before, changed = 0;
922
      unsigned short memoffset = 0x01BE; /* first partition flag is here */
923
      for (i = 0; i < 4; i++) {
924
        flag_before = buff[memoffset];
925
        buff[memoffset] &= 127;
926
        if (i == partid) buff[memoffset] |= 0x80;
927
        if (flag_before != buff[memoffset]) changed++;
928
        memoffset += 16; /* jump to next partition entry */
929
      }
930
      /* do I need to update the MBR? */
931
      if (changed != 0) READ_OR_WRITE_MBR(MBR_WRITE, buff, driveid | 0x80);
932
    }
933
 
934
    snprintf(buff, sizeof(buff), "%c:\\TEMP", cselecteddrive);
1942 mateusz.vi 935
    mkdir(buff);
936
    return(0);
937
  }
28 mv_fox 938
}
939
 
940
 
280 mateuszvis 941
/* generates locales-related configurations and writes them to file (this
942
 * is used to compute autoexec.bat content) */
943
static void genlocalesconf(FILE *fd, const struct slocales *locales) {
944
 
945
  fprintf(fd, "SET LANG=%s\r\n", locales->lang);
946
 
947
  if (locales->egafile > 0) {
948
    fprintf(fd, "DISPLAY CON=(EGA,,1)\r\n");
949
    if (locales->egafile == 1) {
950
      fprintf(fd, "MODE CON CP PREPARE=((%u) %%DOSDIR%%\\CPI\\EGA.CPX)\r\n", locales->codepage);
951
    } else {
1908 mateusz.vi 952
      fprintf(fd, "MODE CON CP PREPARE=((%u) %%DOSDIR%%\\CPI\\EGA%u.CPX)\r\n", locales->codepage, locales->egafile);
280 mateuszvis 953
    }
954
    fprintf(fd, "MODE CON CP SELECT=%u\r\n", locales->codepage);
955
  }
956
 
957
  if (locales->keybfile > 0) {
1659 bttr 958
    fprintf(fd, "KEYB %s,%d,%%DOSDIR%%\\", locales->keybcode, locales->codepage);
280 mateuszvis 959
    if (locales->keybfile == 1) {
960
      fprintf(fd, "KEYBOARD.SYS");
961
    } else {
1908 mateusz.vi 962
      fprintf(fd, "KEYBRD%u.SYS", locales->keybfile);
280 mateuszvis 963
    }
964
    if (locales->keybid != 0) fprintf(fd, " /ID:%d", locales->keybid);
965
    fprintf(fd, "\r\n");
966
  }
967
}
968
 
969
 
1946 mateusz.vi 970
/* get the DOS "current drive" (0=A:, 1=B:, etc) */
971
static unsigned char get_cur_drive(void);
972
#pragma aux get_cur_drive = \
973
"mov ah, 0x19" /* DOS 1+ GET CURRENT DEFAULT DRIVE */ \
974
"int 0x21" \
975
modify [ah] \
976
value [al]
977
 
978
 
979
/* generates configuration files on the dest drive, this is run once system
980
 * booted successfully on the dst drive (postinst stage) */
1950 mateusz.vi 981
static void bootfilesgen(void) {
28 mv_fox 982
  char buff[128];
983
  FILE *fd;
1946 mateusz.vi 984
  unsigned char bootdrv = get_cur_drive() + 'A';
1950 mateusz.vi 985
  struct slocales locales;
1930 mateusz.vi 986
 
1950 mateusz.vi 987
  /* load locales from ZLOCALES.DAT */
988
  fd = fopen("ZLOCALES.DAT", "rb");
989
  if (fd == NULL) return;
990
  fread(&locales, sizeof(struct slocales), 1, fd);
991
  fclose(fd);
992
 
993
  svarlang_load("INSTALL.LNG", locales.lang);
994
 
1930 mateusz.vi 995
  /****************
996
   * CONFIG.SYS ***
997
   ****************/
1946 mateusz.vi 998
  snprintf(buff, sizeof(buff), "%c:\\CONFIG.SYS", bootdrv);
53 mv_fox 999
  fd = fopen(buff, "wb");
1000
  if (fd == NULL) return;
1751 mateusz.vi 1001
  fprintf(fd, "; SvarDOS kernel configuration\r\n"
1002
              "\r\n"
1003
              "; highest allowed drive letter\r\n"
1004
              "LASTDRIVE=Z\r\n"
1005
              "\r\n"
1006
              "; max. number of files that programs are allowed to open simultaneously\r\n"
1007
              "FILES=25\r\n");
1008
  fprintf(fd, "\r\n"
1009
              "; XMS memory driver\r\n"
1930 mateusz.vi 1010
              "DEVICE=%c:\\SVARDOS\\HIMEMX.EXE\r\n", bootdrv);
1751 mateusz.vi 1011
  fprintf(fd, "\r\n"
1012
              "; try moving DOS to upper memory, then to high memory\r\n"
1013
              "DOS=UMB,HIGH\r\n");
1014
  fprintf(fd, "\r\n"
1930 mateusz.vi 1015
              "; command interpreter (shell) location and environment size\r\n"
1016
              "SHELL=%c:\\COMMAND.COM /E:512 /P\r\n", bootdrv);
1751 mateusz.vi 1017
  fprintf(fd, "\r\n"
1908 mateusz.vi 1018
              "; NLS configuration\r\n");
1950 mateusz.vi 1019
  fprintf(fd, "COUNTRY=%03u,%u,%c:\\SVARDOS\\COUNTRY.SYS\r\n", locales.countryid, locales.codepage, bootdrv);
1751 mateusz.vi 1020
  fprintf(fd, "\r\n"
1021
              "; CD-ROM driver initialization\r\n"
1930 mateusz.vi 1022
              ";DEVICE=%c:\\DRIVERS\\VIDECDD\\VIDE-CDD.SYS /D:SVCD0001\r\n", bootdrv);
53 mv_fox 1023
  fclose(fd);
1930 mateusz.vi 1024
 
1025
  /****************
1026
   * AUTOEXEC.BAT *
1027
   ****************/
1028
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\AUTOEXEC.BAT", bootdrv);
28 mv_fox 1029
  fd = fopen(buff, "wb");
1930 mateusz.vi 1030
  if (fd == NULL) {
1031
    return;
1032
  } else {
1033
    char *autoexec_bat1 =
1034
      "@ECHO OFF\r\n"
1935 mateusz.vi 1035
      "SET TEMP=#:\\TEMP\r\n"
1036
      "SET DOSDIR=#:\\SVARDOS\r\n"
1930 mateusz.vi 1037
      "SET NLSPATH=%DOSDIR%\\NLS\r\n"
1038
      "SET DIRCMD=/O/P\r\n"
1946 mateusz.vi 1039
      "SET WATTCP.CFG=%DOSDIR%\r\n"
1930 mateusz.vi 1040
      "PATH %DOSDIR%\r\n"
1041
      "PROMPT $P$G\r\n"
1042
      "\r\n"
1043
      "REM enable CPU power saving\r\n"
1044
      "FDAPM ADV:REG\r\n"
1045
      "\r\n";
1046
    char *autoexec_bat2 =
1047
      "REM Uncomment the line below for CDROM support\r\n"
1048
      "REM SHSUCDX /d:SVCD0001\r\n"
1049
      "\r\n"
1050
      "ECHO.\r\n";
1051
 
1935 mateusz.vi 1052
    /* replace all '#' occurences by bootdrive */
1053
    strtr(autoexec_bat1, '#', bootdrv);
1930 mateusz.vi 1054
 
1055
    /* write all to file */
1056
    fputs(autoexec_bat1, fd);
1950 mateusz.vi 1057
    genlocalesconf(fd, &locales);
1930 mateusz.vi 1058
    fputs(autoexec_bat2, fd);
1059
 
1060
    fprintf(fd, "ECHO %s\r\n", svarlang_strid(0x0600)); /* "Welcome to SvarDOS!" */
1061
    fclose(fd);
1062
  }
1063
 
200 mateuszvis 1064
  /*** CREATE DIRECTORY FOR CONFIGURATION FILES ***/
1930 mateusz.vi 1065
  snprintf(buff, sizeof(buff), "%c:\\SVARDOS", bootdrv);
200 mateuszvis 1066
  mkdir(buff);
1930 mateusz.vi 1067
 
1068
  /****************
1069
   * PKG.CFG      *
1070
   ****************/
1935 mateusz.vi 1071
  snprintf(buff, sizeof(buff), "%c:\\SVARDOS\\PKG.CFG", bootdrv);
277 mateuszvis 1072
  fd = fopen(buff, "wb");
1930 mateusz.vi 1073
  if (fd == NULL) {
1074
    return;
1075
  } else {
1076
    char *pkg_cfg =
1077
      "# pkg config file - specifies locations where packages should be installed\r\n"
1078
      "\r\n"
1079
      "# System boot drive\r\n"
1935 mateusz.vi 1080
      "BOOTDRIVE @\r\n"
1930 mateusz.vi 1081
      "\r\n"
1082
      "# DOS core binaries\r\n"
1083
      "DIR BIN @:\\SVARDOS\r\n"
1084
      "\r\n"
1085
      "# Programs\r\n"
1086
      "DIR PROGS @:\\\r\n"
1087
      "\r\n"
1088
      "# Games \r\n"
1089
      "DIR GAMES @:\\\r\n"
1090
      "\r\n"
1091
      "# Drivers\r\n"
1092
      "DIR DRIVERS @:\\DRIVERS\r\n"
1093
      "\r\n"
1094
      "# Development tools\r\n"
1095
      "DIR DEVEL @:\\DEVEL\r\n";
1096
 
1097
    /* replace all @ by the actual boot drive */
1098
    strtr(pkg_cfg, '@', bootdrv);
1099
 
1100
    /* write to file */
1101
    fputs(pkg_cfg, fd);
1102
    fclose(fd);
1103
  }
1104
 
1946 mateusz.vi 1105
  /****************
1106
   * PICOTCP      *
1107
   ****************/
1930 mateusz.vi 1108
  /* TODO (or not? maybe not that useful) */
1109
 
1946 mateusz.vi 1110
  /****************
1111
   * WATTCP.CFG   *
1112
   ****************/
1113
  snprintf(buff, sizeof(buff), "%c:\\SVARDOS\\WATTCP.CFG", bootdrv);
303 mateuszvis 1114
  fd = fopen(buff, "wb");
1115
  if (fd == NULL) return;
1116
  fprintf(fd, "my_ip = dhcp\r\n"
1117
              "#my_ip = 192.168.0.7\r\n"
1118
              "#netmask = 255.255.255.0\r\n"
1119
              "#nameserver = 192.168.0.1\r\n"
1120
              "#nameserver = 192.168.0.2\r\n"
554 mateuszvis 1121
              "#gateway = 192.168.0.1\r\n");
303 mateuszvis 1122
  fclose(fd);
1946 mateusz.vi 1123
 
1124
  /****************
1125
   * POSTINST.BAT *
1126
   ****************/
1127
  /* create the postinst.bat file for actual installation of packages */
1950 mateusz.vi 1128
  fd = fopen("POSTINST.BAT", "wb");
1129
  if (fd == NULL) return;
1946 mateusz.vi 1130
  fprintf(fd,
1131
    "@ECHO OFF\r\n"
1132
    "SET DOSDIR=%c:\\SVARDOS\r\n"
1133
    "PATH %%DOSDIR%%\r\n"
1134
    "ECHO INSTALLING PACKAGES\r\n"
1135
    "COPY \\COMMAND.COM \\CMD.COM\r\n" /* move COMMAND.COM so it does not clashes with the installation of the SVARCOM package */
1136
    "SET COMSPEC=%c:\\CMD.COM\r\n"
1137
    "DEL \\AUTOEXEC.BAT\r\n"
1138
    "COPY AUTOEXEC.BAT \\\r\n"
1950 mateusz.vi 1139
    "DEL AUTOEXEC.BAT\r\n"
1140
    "DEL ZLOCALES.DAT\r\n"
1946 mateusz.vi 1141
    "DEL \\COMMAND.COM\r\n"
1142
    "DEL \\KERNEL.SYS\r\n" /* KERNEL.SYS will be installed from the package in a moment */
1982 mateusz.vi 1143
    "FOR %%%%P IN (*.SVP) DO PKG INOWARN %%%%P\r\n" /* install packages (with warnings muted) */
1946 mateusz.vi 1144
    "DEL *.SVP\r\n", bootdrv, bootdrv);
1145
 
1146
  /* restore COMSPEC and do some cleanup */
1147
  fprintf(fd, "DEL pkg.exe\r\n"
1148
              "DEL install.com\r\n"
1149
              "DEL install.lng\r\n"
1150
              "SET COMSPEC=\\COMMAND.COM\r\n"
1151
              "DEL \\CMD.COM\r\n");
1152
  /* print out the "installation over" message (load codepage first, now that MODE is installed) */
1950 mateusz.vi 1153
  genlocalesconf(fd, &locales);
1946 mateusz.vi 1154
  fprintf(fd, "ECHO.\r\n"
1155
              "ECHO ");
1156
  fprintf(fd, svarlang_strid(0x0502)); /* "SvarDOS installation is over. Please restart your computer now" */
1157
  fprintf(fd, "\r\n"
1158
              "ECHO.\r\n");
1159
  fclose(fd);
1160
 
28 mv_fox 1161
}
1162
 
1163
 
1942 mateusz.vi 1164
static int copypackages(char drvletter, const struct slocales *locales) {
192 mateuszvis 1165
  char pkglist[512];
30 mv_fox 1166
  int i, pkglistlen;
192 mateuszvis 1167
  size_t pkglistflen;
280 mateuszvis 1168
  char buff[1024]; /* must be *at least* 1 sector big for efficient file copying */
1169
  FILE *fd = NULL;
192 mateuszvis 1170
  char *pkgptr;
1942 mateusz.vi 1171
 
79 mv_fox 1172
  newscreen(3);
1942 mateusz.vi 1173
 
192 mateuszvis 1174
  /* load pkg list */
1175
  fd = fopen("install.lst", "rb");
1176
  if (fd == NULL) {
1664 mateusz.vi 1177
    mdr_cout_str(10, 30, "ERROR: INSTALL.LST NOT FOUND", COLOR_BODY, 80);
1661 mateusz.vi 1178
    mdr_dos_getkey();
192 mateuszvis 1179
    return(-1);
1180
  }
1125 mateusz.vi 1181
  pkglistflen = fread(pkglist, 1, sizeof(pkglist) - 2, fd);
192 mateuszvis 1182
  fclose(fd);
1125 mateusz.vi 1183
  if (pkglistflen == sizeof(pkglist) - 2) {
1664 mateusz.vi 1184
    mdr_cout_str(10, 30, "ERROR: INSTALL.LST TOO LARGE", COLOR_BODY, 80);
1661 mateusz.vi 1185
    mdr_dos_getkey();
192 mateuszvis 1186
    return(-1);
1187
  }
1125 mateusz.vi 1188
  /* mark the end of list */
1189
  pkglist[pkglistflen] = 0;
1190
  pkglist[pkglistflen + 1] = 0xff;
192 mateuszvis 1191
  /* replace all \r and \n chars by 0 bytes, and count the number of packages */
1192
  pkglistlen = 0;
1193
  for (i = 0; i < pkglistflen; i++) {
1194
    switch (pkglist[i]) {
1195
      case '\n':
1196
        pkglistlen++;
1197
        /* FALLTHRU */
1198
      case '\r':
1199
        pkglist[i] = 0;
1200
        break;
1201
    }
1202
  }
280 mateuszvis 1203
 
1930 mateusz.vi 1204
  /* copy pkg.exe, install.com and install.lng to the new drive, along with all packages */
1942 mateusz.vi 1205
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\PKG.EXE", drvletter);
1930 mateusz.vi 1206
  fcopy(buff, buff + 8, buff, sizeof(buff));
1942 mateusz.vi 1207
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\INSTALL.COM", drvletter);
1930 mateusz.vi 1208
  fcopy(buff, buff + 8, buff, sizeof(buff));
1942 mateusz.vi 1209
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\INSTALL.LNG", drvletter);
1930 mateusz.vi 1210
  fcopy(buff, buff + 8, buff, sizeof(buff));
1211
 
280 mateuszvis 1212
  /* copy packages */
192 mateuszvis 1213
  for (i = 0;; i++) {
1125 mateusz.vi 1214
    RETRY_ENTIRE_LIST:
1215
 
192 mateuszvis 1216
    /* move forward to nearest entry or end of list */
1125 mateusz.vi 1217
    for (pkgptr = pkglist; *pkgptr == 0; pkgptr++);
1218
    if (*pkgptr == 0xff) break; /* end of list: means all packages have been processed */
1219
 
1220
    /* is this package present on the floppy disk? */
1221
    TRY_NEXTPKG:
1222
    sprintf(buff, "%s.svp", pkgptr);
1669 mateusz.vi 1223
    if (!fileexists(buff)) {
1125 mateusz.vi 1224
      while (*pkgptr != 0) pkgptr++;
1225
      while (*pkgptr == 0) pkgptr++;
1226
      /* end of list? ask for next floppy, there's nothing interesting left on this one */
1227
      if (*pkgptr == 0xff) {
1664 mateusz.vi 1228
        putstringnls(12, 1, COLOR_BODY, 4, 1); /* "INSERT THE DISK THAT CONTAINS THE REQUIRED FILE AND PRESS ANY KEY" */
1661 mateusz.vi 1229
        mdr_dos_getkey();
1664 mateusz.vi 1230
        video_putstringfix(12, 1, COLOR_BODY, "", 80); /* erase the 'insert disk' message */
1125 mateusz.vi 1231
        goto RETRY_ENTIRE_LIST;
1232
      }
1233
      goto TRY_NEXTPKG;
1234
    }
1235
 
1953 mateusz.vi 1236
    /* copy the package */
1237
    snprintf(buff, sizeof(buff), svarlang_strid(0x0400), i+1, pkglistlen, pkgptr); /* "Copying package %d/%d: %s" */
36 mv_fox 1238
    strcat(buff, "       ");
1664 mateusz.vi 1239
    mdr_cout_str(10, 1, buff, COLOR_BODY, 40);
1125 mateusz.vi 1240
 
1241
    /* proceed with package copy */
1942 mateusz.vi 1242
    sprintf(buff, "%c:\\TEMP\\%s.svp", drvletter, pkgptr);
1930 mateusz.vi 1243
    if (fcopy(buff, buff + 8, buff, sizeof(buff)) != 0) {
1664 mateusz.vi 1244
      mdr_cout_str(10, 30, "READ ERROR", COLOR_BODY, 80);
1661 mateusz.vi 1245
      mdr_dos_getkey();
192 mateuszvis 1246
      return(-1);
55 mv_fox 1247
    }
1125 mateusz.vi 1248
    /* jump to next entry or end of list and zero out the pkg name in the process */
1249
    while ((*pkgptr != 0) && (*pkgptr != 0xff)) {
1250
      *pkgptr = 0;
1251
      pkgptr++;
1252
    }
28 mv_fox 1253
  }
1934 mateusz.vi 1254
 
1950 mateusz.vi 1255
  /* dump locales into ZLOCALES.DAT so the 2nd stage install can get them back */
1256
  snprintf(buff, sizeof(buff), "%c:\\TEMP\\ZLOCALES.DAT", drvletter);
1934 mateusz.vi 1257
  fd = fopen(buff, "wb");
1258
  if (fd == NULL) return(-1);
1950 mateusz.vi 1259
  fwrite(locales, sizeof(struct slocales), 1, fd);
280 mateuszvis 1260
  fclose(fd);
1261
 
1946 mateusz.vi 1262
  /* prepare a dummy autoexec.bat that will exec install and call temp\postinst.bat */
1942 mateusz.vi 1263
  snprintf(buff, sizeof(buff), "%c:\\autoexec.bat", drvletter);
280 mateuszvis 1264
  fd = fopen(buff, "wb");
1265
  if (fd == NULL) return(-1);
1266
  fprintf(fd, "@ECHO OFF\r\n"
1950 mateusz.vi 1267
              "CD TEMP\r\n"
1946 mateusz.vi 1268
              "install\r\n"   /* installer will run in 2nd stage (generating autoexec.bat, pkg.cfg and stuff) */
280 mateuszvis 1269
              "postinst.bat\r\n");
1270
  fclose(fd);
1271
 
192 mateuszvis 1272
  return(0);
28 mv_fox 1273
}
1274
 
1275
 
42 mv_fox 1276
static void finalreboot(void) {
56 mv_fox 1277
  int y = 9;
79 mv_fox 1278
  newscreen(2);
1673 mateusz.vi 1279
  y += putstringnls(y, 1, COLOR_BODY, 5, 0); /* "Your computer will reboot now." */
1280
  y += putstringnls(y, 1, COLOR_BODYWARN, 5, 1); /* Please remove the installation disk from your drive" */
1664 mateusz.vi 1281
  putstringnls(++y, 1, COLOR_BODY, 0, 5); /* "Press any key..." */
1661 mateusz.vi 1282
  mdr_dos_getkey();
42 mv_fox 1283
  reboot();
1284
}
1285
 
1286
 
192 mateuszvis 1287
static void loadcp(const struct slocales *locales) {
42 mv_fox 1288
  char buff[64];
67 mv_fox 1289
  if (locales->codepage == 437) return;
1662 mateusz.vi 1290
  mdr_cout_locate(1, 0);
67 mv_fox 1291
  if (locales->egafile == 1) {
310 mateuszvis 1292
    snprintf(buff, sizeof(buff), "MODE CON CP PREP=((%u) EGA.CPX) > NUL", locales->codepage);
42 mv_fox 1293
  } else {
310 mateuszvis 1294
    snprintf(buff, sizeof(buff), "MODE CON CP PREP=((%u) EGA%d.CPX) > NUL", locales->codepage, locales->egafile);
42 mv_fox 1295
  }
1918 mateusz.vi 1296
  exec(buff);
67 mv_fox 1297
  snprintf(buff, sizeof(buff), "MODE CON CP SEL=%u > NUL", locales->codepage);
1918 mateusz.vi 1298
  exec(buff);
42 mv_fox 1299
  /* below I re-init the video controller - apparently this is required if
65 mv_fox 1300
   * I want the new glyph symbols to be actually applied, at least some
1301
   * (broken?) BIOSes, like VBox, apply glyphs only at next video mode change */
1908 mateusz.vi 1302
  _asm {
1303
    push bx
1304
    mov ah, 0x0F  /* get current video mode */
1305
    int 0x10      /* al contains the current video mode now */
1306
    or al, 128    /* set high bit of AL to instruct BIOS not to flush VRAM's content (EGA+) */
1307
    xor ah, ah    /* re-set video mode (to whatever is set in AL) */
1308
    int 0x10
1309
    pop bx
42 mv_fox 1310
  }
1311
}
1312
 
200 mateuszvis 1313
 
1671 mateusz.vi 1314
int main(void) {
1950 mateusz.vi 1315
  struct slocales locales;
28 mv_fox 1316
  int targetdrv;
73 mv_fox 1317
  int action;
28 mv_fox 1318
 
1911 mateusz.vi 1319
  /* setup an internal int 24h handler ("always fail") so DOS does not output
1320
   * the ugly "abort, retry, fail" messages */
1918 mateusz.vi 1321
  install_int24();
908 mateusz.vi 1322
 
1930 mateusz.vi 1323
  /* init screen and detect mono adapters */
1324
  if (mdr_cout_init(NULL, NULL) == 0) {
1325
    /* overload color scheme with mono settings */
1326
    COLOR_TITLEBAR = 0x70;
1327
    COLOR_TITLEVER = 0x70;
1328
    COLOR_BODY = 0x07;
1329
    COLOR_BODYWARN = 0x07;
1330
    COLOR_SELECT = 0x70;
1331
    COLOR_SELECTCUR = 0x07;
1332
  }
1333
 
1334
  /* is it stage 2 of the installation? */
1950 mateusz.vi 1335
  if (fileexists("ZLOCALES.DAT")) goto GENCONF;
1930 mateusz.vi 1336
 
1671 mateusz.vi 1337
  /* read the svardos build revision (from floppy label) */
1338
  {
1339
    const char *fspec = "*.*";
1340
    const char *res = (void*)0x9E; /* default DTA is at PSP:80h, field 1Eh of DTA is the ASCIZ file name */
868 mateusz.vi 1341
 
1671 mateusz.vi 1342
    _asm {
1343
      push cx
1344
      push dx
1345
 
1346
      mov ax, 0x4e00  /* findfirst */
1347
      mov cx, 0x08    /* file attr mask, 0x08 = volume label */
1348
      mov dx, fspec
1349
      int 0x21
1350
      jnc good
1672 mateusz.vi 1351
      mov bx, res
1352
      mov [bx], byte ptr 0
1671 mateusz.vi 1353
      good:
1354
 
1355
      pop dx
1356
      pop cx
1357
    }
1358
 
1359
    memcpy(BUILDSTRING, res, 12);
1360
  }
1361
 
73 mv_fox 1362
 SelectLang:
1950 mateusz.vi 1363
  action = selectlang(&locales); /* welcome to svardos, select your language */
1930 mateusz.vi 1364
  if (action != MENUNEXT) goto QUIT;
1950 mateusz.vi 1365
  loadcp(&locales);
1366
  svarlang_load("INSTALL.LNG", locales.lang); /* NLS support */
865 mateusz.vi 1367
 
1950 mateusz.vi 1368
  action = selectkeyb(&locales);  /* what keyb layout should we use? */
1930 mateusz.vi 1369
  if (action == MENUQUIT) goto QUIT;
1908 mateusz.vi 1370
  if (action == MENUPREV) goto SelectLang;
73 mv_fox 1371
 
1372
 WelcomeScreen:
190 mateuszvis 1373
  action = welcomescreen(); /* what svardos is, ask whether to run live dos or install */
1930 mateusz.vi 1374
  if (action == MENUQUIT) goto QUIT;
1950 mateusz.vi 1375
  if (action == MENUPREV) goto SelectLang;
1669 mateusz.vi 1376
 
1942 mateusz.vi 1377
 SelDriveScreen:
1378
  targetdrv = selectdrive();
1930 mateusz.vi 1379
  if (targetdrv == MENUQUIT) goto QUIT;
73 mv_fox 1380
  if (targetdrv == MENUPREV) goto WelcomeScreen;
1942 mateusz.vi 1381
 
1382
  action = preparedrive(targetdrv); /* what drive should we install to? check avail. space */
1383
  if (action == MENUQUIT) goto QUIT;
1384
  if (action == MENUPREV) goto SelDriveScreen;
1944 mateusz.vi 1385
  targetdrv = (targetdrv & 0xff) + 'A'; /* convert the part+hd+drv value to a DOS letter */
1942 mateusz.vi 1386
 
1387
  /* copy packages to dst drive */
1950 mateusz.vi 1388
  if (copypackages(targetdrv, &locales) != 0) goto QUIT;
1930 mateusz.vi 1389
  finalreboot(); /* remove the install medium and reboot */
73 mv_fox 1390
 
1930 mateusz.vi 1391
  goto QUIT;
1392
 
1393
 GENCONF: /* second stage of the installation (run from the destination disk) */
1950 mateusz.vi 1394
  bootfilesgen(); /* generate boot files and other configurations */
1930 mateusz.vi 1395
 
1396
 QUIT:
1662 mateusz.vi 1397
  mdr_cout_locate(0, 0);
1398
  mdr_cout_close();
28 mv_fox 1399
  return(0);
1400
}