1 /*
2 * This file is part of DGD, https://github.com/dworkin/dgd
3 * Copyright (C) 1993-2010 Dworkin B.V.
4 * Copyright (C) 2010-2013 DGD Authors (see the commit log for details)
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 # define INCLUDE_FILE_IO
21 # define INCLUDE_CTYPE
22 # include "dgd.h"
23 # include "str.h"
24 # include "array.h"
25 # include "object.h"
26 # include "xfloat.h"
27 # include "interpret.h"
28 # include "data.h"
29 # include "path.h"
30 # include "editor.h"
31 # include "call_out.h"
32 # include "comm.h"
33 # include "version.h"
34 # include "macro.h"
35 # include "token.h"
36 # include "ppcontrol.h"
37 # include "node.h"
38 # include "parser.h"
39 # include "compile.h"
40 # include "control.h"
41 # include "csupport.h"
42 # include "table.h"
43
44 typedef struct {
45 char *name; /* name of the option */
46 short type; /* option type */
47 bool resolv; /* TRUE if path name must be resolved */
48 bool set; /* TRUE if option is set */
49 Uint low, high; /* lower and higher bound, for numeric values */
50 union {
51 long num; /* numeric value */
52 char *str; /* string value */
53 } u;
54 } config;
55
56 static config conf[] = {
57 # define ARRAY_SIZE 0
58 { "array_size", INT_CONST, FALSE, FALSE,
59 1, USHRT_MAX / 2 },
60 # define AUTO_OBJECT 1
61 { "auto_object", STRING_CONST, TRUE },
62 # define BINARY_PORT 2
63 { "binary_port", '[', FALSE, FALSE,
64 1, USHRT_MAX },
65 # define CACHE_SIZE 3
66 { "cache_size", INT_CONST, FALSE, FALSE,
67 1, UINDEX_MAX },
68 # define CALL_OUTS 4
69 { "call_outs", INT_CONST, FALSE, FALSE,
70 0, UINDEX_MAX - 1 },
71 # define CREATE 5
72 { "create", STRING_CONST },
73 # define DIRECTORY 6
74 { "directory", STRING_CONST },
75 # define DRIVER_OBJECT 7
76 { "driver_object", STRING_CONST, TRUE },
77 # define DUMP_FILE 8
78 { "dump_file", STRING_CONST },
79 # define DUMP_INTERVAL 9
80 { "dump_interval", INT_CONST },
81 # define DYNAMIC_CHUNK 10
82 { "dynamic_chunk", INT_CONST, FALSE, FALSE,
83 1024 },
84 # define ED_TMPFILE 11
85 { "ed_tmpfile", STRING_CONST },
86 # define EDITORS 12
87 { "editors", INT_CONST, FALSE, FALSE,
88 0, EINDEX_MAX },
89 # define HOTBOOT 13
90 { "hotboot", '(' },
91 # define INCLUDE_DIRS 14
92 { "include_dirs", '(' },
93 # define INCLUDE_FILE 15
94 { "include_file", STRING_CONST, TRUE },
95 # define MODULES 16
96 { "modules", '(' },
97 # define OBJECTS 17
98 { "objects", INT_CONST, FALSE, FALSE,
99 2, UINDEX_MAX },
100 # define PORTS 18
101 { "ports", INT_CONST, FALSE, FALSE,
102 1, 32 },
103 # define SECTOR_SIZE 19
104 { "sector_size", INT_CONST, FALSE, FALSE,
105 512, 65535 },
106 # define STATIC_CHUNK 20
107 { "static_chunk", INT_CONST },
108 # define SWAP_FILE 21
109 { "swap_file", STRING_CONST },
110 # define SWAP_FRAGMENT 22
111 { "swap_fragment", INT_CONST, FALSE, FALSE,
112 0, SW_UNUSED },
113 # define SWAP_SIZE 23
114 { "swap_size", INT_CONST, FALSE, FALSE,
115 1024, SW_UNUSED },
116 # define TELNET_PORT 24
117 { "telnet_port", '[', FALSE, FALSE,
118 1, USHRT_MAX },
119 # define TYPECHECKING 25
120 { "typechecking", INT_CONST, FALSE, FALSE,
121 0, 2 },
122 # define USERS 26
123 { "users", INT_CONST, FALSE, FALSE,
124 1, EINDEX_MAX },
125 # define NR_OPTIONS 27
126 };
127
128
129 typedef struct { char fill; char c; } alignc;
130 typedef struct { char fill; short s; } aligns;
131 typedef struct { char fill; Int i; } aligni;
132 typedef struct { char fill; char *p; } alignp;
133 typedef struct { char c; } alignz;
134
135 # define FORMAT_VERSION 14
136
137 # define DUMP_VALID 0 /* valid dump flag */
138 # define DUMP_VERSION 1 /* snapshot version number */
139 # define DUMP_MODEL 2 /* 0: vanilla DGD, 1: iChat DGD */
140 # define DUMP_TYPECHECK 3 /* global typechecking */
141 # define DUMP_SECSIZE 4 /* sector size */
142 # define DUMP_TYPE 4 /* first XX bytes, dump type */
143 # define DUMP_HEADERSZ 28 /* header size */
144 # define DUMP_STARTTIME 28 /* start time */
145 # define DUMP_ELAPSED 32 /* elapsed time */
146 # define DUMP_VSTRING 42 /* version string */
147
148 # define FLAGS_PARTIAL 0x01 /* partial snapshot */
149 # define FLAGS_HOTBOOT 0x04 /* hotboot snapshot */
150
151 typedef char dumpinfo[64];
152
153 static dumpinfo header; /* snapshot header */
154 # define s0 (header[ 6]) /* short, msb */
155 # define s1 (header[ 7]) /* short, lsb */
156 # define i0 (header[ 8]) /* Int, msb */
157 # define i1 (header[ 9])
158 # define i2 (header[10])
159 # define i3 (header[11]) /* Int, lsb */
160 # define utsize (header[20]) /* sizeof(uindex) + sizeof(ssizet) */
161 # define desize (header[21]) /* sizeof(sector) + sizeof(eindex) */
162 # define psize (header[22]) /* sizeof(char*), upper nibble reserved */
163 # define calign (header[23]) /* align(char) */
164 # define salign (header[24]) /* align(short) */
165 # define ialign (header[25]) /* align(Int) */
166 # define palign (header[26]) /* align(char*) */
167 # define zalign (header[27]) /* align(struct) */
168 # define zero1 (header[36]) /* reserved (0) */
169 # define zero2 (header[37]) /* reserved (0) */
170 # define zero3 (header[38]) /* reserved (0) */
171 # define zero4 (header[39]) /* reserved (0) */
172 # define dflags (header[40]) /* flags */
173 # define zero5 (header[41]) /* reserved (0) */
174 static int ualign; /* align(uindex) */
175 static int talign; /* align(ssizet) */
176 static int dalign; /* align(sector) */
177 static int ealign; /* align(eindex) */
178 static dumpinfo rheader; /* restored header */
179 # define rs0 (rheader[ 6]) /* short, msb */
180 # define rs1 (rheader[ 7]) /* short, lsb */
181 # define ri0 (rheader[ 8]) /* Int, msb */
182 # define ri1 (rheader[ 9])
183 # define ri2 (rheader[10])
184 # define ri3 (rheader[11]) /* Int, lsb */
185 # define rutsize (rheader[20]) /* sizeof(uindex) + sizeof(ssizet) */
186 # define rdesize (rheader[21]) /* sizeof(sector) + sizeof(eindex) */
187 # define rpsize (rheader[22]) /* sizeof(char*), upper nibble reserved */
188 # define rcalign (rheader[23]) /* align(char) */
189 # define rsalign (rheader[24]) /* align(short) */
190 # define rialign (rheader[25]) /* align(Int) */
191 # define rpalign (rheader[26]) /* align(char*) */
192 # define rzalign (rheader[27]) /* align(struct) */
193 # define rzero1 (rheader[36]) /* reserved (0) */
194 # define rzero2 (rheader[37]) /* reserved (0) */
195 # define rzero3 (rheader[38]) /* reserved (0) */
196 # define rzero4 (rheader[39]) /* reserved (0) */
197 # define rdflags (rheader[40]) /* flags */
198 # define rzero5 (rheader[41]) /* reserved (0) */
199 static int rusize; /* sizeof(uindex) */
200 static int rtsize; /* sizeof(ssizet) */
201 static int rdsize; /* sizeof(sector) */
202 static int resize; /* sizeof(eindex) */
203 static int rualign; /* align(uindex) */
204 static int rtalign; /* align(ssizet) */
205 static int rdalign; /* align(sector) */
206 static int realign; /* align(eindex) */
207 static Uint starttime; /* start time */
208 static Uint elapsed; /* elapsed time */
209 static Uint boottime; /* boot time */
210
211 /*
212 * NAME: conf->dumpinit()
213 * DESCRIPTION: initialize snapshot information
214 */
conf_dumpinit()215 static void conf_dumpinit()
216 {
217 short s;
218 Int i;
219 alignc cdummy;
220 aligns sdummy;
221 aligni idummy;
222 alignp pdummy;
223
224 header[DUMP_VALID] = TRUE; /* valid dump flag */
225 header[DUMP_VERSION] = FORMAT_VERSION; /* snapshot version number */
226 header[DUMP_MODEL] = 0; /* vanilla DGD */
227 header[DUMP_TYPECHECK] = conf[TYPECHECKING].u.num;
228 header[DUMP_SECSIZE + 0] = conf[SECTOR_SIZE].u.num >> 8;
229 header[DUMP_SECSIZE + 1] = conf[SECTOR_SIZE].u.num;
230 strcpy(header + DUMP_VSTRING, VERSION);
231
232 starttime = boottime = P_time();
233
234 s = 0x1234;
235 i = 0x12345678L;
236 s0 = strchr((char *) &s, 0x12) - (char *) &s;
237 s1 = strchr((char *) &s, 0x34) - (char *) &s;
238 i0 = strchr((char *) &i, 0x12) - (char *) &i;
239 i1 = strchr((char *) &i, 0x34) - (char *) &i;
240 i2 = strchr((char *) &i, 0x56) - (char *) &i;
241 i3 = strchr((char *) &i, 0x78) - (char *) &i;
242 utsize = sizeof(uindex) | (sizeof(ssizet) << 4);
243 desize = sizeof(sector) | (sizeof(eindex) << 4);
244 psize = sizeof(char*) | (sizeof(char) << 4);
245 calign = (char *) &cdummy.c - (char *) &cdummy.fill;
246 salign = (char *) &sdummy.s - (char *) &sdummy.fill;
247 ialign = (char *) &idummy.i - (char *) &idummy.fill;
248 palign = (char *) &pdummy.p - (char *) &pdummy.fill;
249 zalign = sizeof(alignz);
250 zero1 = zero2 = 0;
251
252 ualign = (sizeof(uindex) == sizeof(short)) ? salign : ialign;
253 talign = (sizeof(ssizet) == sizeof(short)) ? salign : ialign;
254 dalign = (sizeof(sector) == sizeof(short)) ? salign : ialign;
255 switch (sizeof(eindex)) {
256 case sizeof(char): ealign = calign; break;
257 case sizeof(short): ealign = salign; break;
258 case sizeof(Int): ealign = ialign; break;
259 }
260 }
261
262 /*
263 * NAME: conf->dump()
264 * DESCRIPTION: dump system state on file
265 */
conf_dump(bool incr,bool boot)266 void conf_dump(bool incr, bool boot)
267 {
268 int fd;
269 Uint etime;
270
271 header[DUMP_VERSION] = FORMAT_VERSION;
272 header[DUMP_TYPECHECK] = conf[TYPECHECKING].u.num;
273 header[DUMP_STARTTIME + 0] = starttime >> 24;
274 header[DUMP_STARTTIME + 1] = starttime >> 16;
275 header[DUMP_STARTTIME + 2] = starttime >> 8;
276 header[DUMP_STARTTIME + 3] = starttime;
277 etime = P_time();
278 if (etime < boottime) {
279 etime = boottime;
280 }
281 etime += elapsed - boottime;
282 header[DUMP_ELAPSED + 0] = etime >> 24;
283 header[DUMP_ELAPSED + 1] = etime >> 16;
284 header[DUMP_ELAPSED + 2] = etime >> 8;
285 header[DUMP_ELAPSED + 3] = etime;
286
287 if (!incr) {
288 o_copy(0);
289 }
290 d_swapout(1);
291 dflags = 0;
292 if (o_dobjects() > 0) {
293 dflags |= FLAGS_PARTIAL;
294 }
295 fd = sw_dump(conf[DUMP_FILE].u.str, dflags & FLAGS_PARTIAL);
296 if (!kf_dump(fd)) {
297 fatal("failed to dump kfun table");
298 }
299 if (!o_dump(fd, incr)) {
300 fatal("failed to dump object table");
301 }
302 if (!pc_dump(fd)) {
303 fatal("failed to dump precompiled objects");
304 }
305 if (!co_dump(fd)) {
306 fatal("failed to dump callout table");
307 }
308 if (boot) {
309 boot = comm_dump(fd);
310 if (boot) {
311 dflags |= FLAGS_HOTBOOT;
312 }
313 }
314
315 sw_dump2(header, sizeof(dumpinfo), incr);
316 }
317
318 /*
319 * NAME: conf->header()
320 * DESCRIPTION: restore a snapshot header
321 */
conf_header(int fd,dumpinfo h)322 static unsigned int conf_header(int fd, dumpinfo h)
323 {
324 unsigned int secsize;
325 off_t offset;
326
327 for (;;) {
328 if (P_read(fd, h, sizeof(dumpinfo)) != sizeof(dumpinfo) ||
329 h[DUMP_VALID] != 1 ||
330 h[DUMP_VERSION] < 2 ||
331 h[DUMP_VERSION] > FORMAT_VERSION) {
332 error("Bad or incompatible restore file header");
333 }
334 secsize = (UCHAR(h[DUMP_SECSIZE + 0]) << 8) |
335 UCHAR(h[DUMP_SECSIZE + 1]);
336 offset = (UCHAR(h[sizeof(dumpinfo) - 4]) << 24) |
337 (UCHAR(h[sizeof(dumpinfo) - 3]) << 16) |
338 (UCHAR(h[sizeof(dumpinfo) - 2]) << 8) |
339 UCHAR(h[sizeof(dumpinfo) - 1]);
340 if (offset == 0) {
341 P_lseek(fd, secsize - sizeof(dumpinfo), SEEK_CUR);
342 return secsize;
343 }
344
345 P_lseek(fd, offset * secsize, SEEK_SET);
346 }
347 }
348
349 /*
350 * NAME: conf->restore()
351 * DESCRIPTION: restore system state from file
352 */
conf_restore(int fd,int fd2)353 static bool conf_restore(int fd, int fd2)
354 {
355 bool conv_co1, conv_co2, conv_co3, conv_lwo, conv_ctrl1, conv_ctrl2,
356 conv_data, conv_type, conv_inherit, conv_time, conv_vm;
357 unsigned int secsize;
358
359 secsize = conf_header(fd, rheader);
360 conv_co1 = conv_co2 = conv_co3 = conv_lwo = conv_ctrl1 = conv_ctrl2 =
361 conv_data = conv_type = conv_inherit = conv_time = conv_vm =
362 FALSE;
363 if (rheader[DUMP_VERSION] < 3) {
364 conv_co1 = TRUE;
365 }
366 if (rheader[DUMP_VERSION] < 4) {
367 conv_lwo = TRUE;
368 }
369 if (rheader[DUMP_VERSION] < 5) {
370 conv_ctrl1 = TRUE;
371 }
372 if (rheader[DUMP_VERSION] < 6) {
373 conv_data = TRUE;
374 rzero1 = rzero2 = 0;
375 }
376 if (rheader[DUMP_VERSION] < 7) {
377 conv_co2 = TRUE;
378 }
379 if (rheader[DUMP_VERSION] < 8) {
380 conv_type = TRUE;
381 }
382 if (rheader[DUMP_VERSION] < 9) {
383 conv_ctrl2 = TRUE;
384 }
385 if (rheader[DUMP_VERSION] < 10) {
386 conv_inherit = TRUE;
387 }
388 if (rheader[DUMP_VERSION] < 11) {
389 conv_co3 = TRUE;
390 }
391 if (rheader[DUMP_VERSION] < 12) {
392 memmove(rheader + 20, rheader + 12, 18);
393 rzero3 = rzero4 = rdflags = rzero5 = 0;
394 }
395 if (rheader[DUMP_VERSION] < 13) {
396 conv_time = TRUE;
397 }
398 if (rheader[DUMP_VERSION] < 14) {
399 conv_vm = TRUE;
400 }
401 header[DUMP_VERSION] = rheader[DUMP_VERSION];
402 if (memcmp(header, rheader, DUMP_TYPE) != 0 || rzero1 != 0 || rzero2 != 0 ||
403 rzero3 != 0 || rzero4 != 0 || rzero5 != 0) {
404 error("Bad or incompatible restore file header");
405 }
406 if (rdflags & FLAGS_PARTIAL) {
407 dumpinfo h;
408
409 /* secondary snapshot required */
410 if (fd2 < 0) {
411 error("Missing secondary snapshot");
412 }
413 conf_header(fd2, h);
414 if (memcmp(rheader, h, DUMP_HEADERSZ) != 0) {
415 error("Secondary snapshot has different type");
416 }
417 sw_restore2(fd2);
418 }
419
420 starttime = (UCHAR(rheader[DUMP_STARTTIME + 0]) << 24) |
421 (UCHAR(rheader[DUMP_STARTTIME + 1]) << 16) |
422 (UCHAR(rheader[DUMP_STARTTIME + 2]) << 8) |
423 UCHAR(rheader[DUMP_STARTTIME + 3]);
424 elapsed = (UCHAR(rheader[DUMP_ELAPSED + 0]) << 24) |
425 (UCHAR(rheader[DUMP_ELAPSED + 1]) << 16) |
426 (UCHAR(rheader[DUMP_ELAPSED + 2]) << 8) |
427 UCHAR(rheader[DUMP_ELAPSED + 3]);
428 rusize = rutsize & 0xf;
429 rtsize = rutsize >> 4;
430 if (rtsize == 0) {
431 rtsize = sizeof(unsigned short); /* backward compat */
432 }
433 rdsize = rdesize & 0xf;
434 resize = rdesize >> 4;
435 if (resize == 0) {
436 resize = sizeof(char); /* backward compat */
437 }
438 if ((rcalign >> 4) != 0) {
439 error("Cannot restore arrsize > 2");
440 }
441 if ((rsalign >> 4) != 0) {
442 error("Cannot restore Int size > 4");
443 }
444 rialign &= 0xf;
445 rualign = (rusize == sizeof(short)) ? rsalign : rialign;
446 rtalign = (rtsize == sizeof(short)) ? rsalign : rialign;
447 rdalign = (rdsize == sizeof(short)) ? rsalign : rialign;
448 switch (resize) {
449 case sizeof(char): realign = rcalign; break;
450 case sizeof(short): realign = rsalign; break;
451 case sizeof(Int): realign = rialign; break;
452 }
453 if (sizeof(uindex) < rusize || sizeof(ssizet) < rtsize ||
454 sizeof(sector) < rdsize) {
455 error("Cannot restore uindex, ssizet or sector of greater width");
456 }
457 if ((rpsize >> 4) > 1) {
458 error("Cannot restore hindex > 1"); /* Hydra only */
459 }
460 rpsize &= 0xf;
461
462 sw_restore(fd, secsize);
463 kf_restore(fd, conv_co1);
464 o_restore(fd, (uindex) ((conv_lwo) ? 1 << (rusize * 8 - 1) : 0),
465 rdflags & FLAGS_PARTIAL);
466 d_init_conv(conv_ctrl1, conv_ctrl2, conv_data, conv_co1, conv_co2,
467 conv_type, conv_inherit, conv_time, conv_vm);
468 pc_restore(fd, conv_inherit);
469 boottime = P_time();
470 co_restore(fd, boottime, conv_co2, conv_co3, conv_time);
471
472 if (fd2 >= 0) {
473 P_close(fd2);
474 }
475
476 return ((rdflags & FLAGS_HOTBOOT) && comm_restore(fd));
477 }
478
479 /*
480 * NAME: conf->dsize()
481 * DESCRIPTION: compute the size and alignment of a struct
482 * 0x000000ff size in snapshot
483 * 0x0000ff00 alignment in snapshot
484 * 0x00ff0000 size
485 * 0xff000000 alignment
486 */
conf_dsize(char * layout)487 Uint conf_dsize(char *layout)
488 {
489 char *p;
490 Uint sz, rsz, al, ral;
491 Uint size, rsize, align, ralign;
492
493 p = layout;
494 size = rsize = 0;
495 align = ralign = 1;
496 sz = rsz = al = ral = 0;
497
498 for (;;) {
499 switch (*p++) {
500 case 'c': /* character */
501 sz = rsz = sizeof(char);
502 al = calign;
503 ral = rcalign;
504 break;
505
506 case 's': /* short */
507 sz = rsz = sizeof(short);
508 al = salign;
509 ral = rsalign;
510 break;
511
512 case 'u': /* uindex */
513 sz = sizeof(uindex);
514 rsz = rusize;
515 al = ualign;
516 ral = rualign;
517 break;
518
519 case 'i': /* Int */
520 sz = rsz = sizeof(Int);
521 al = ialign;
522 ral = rialign;
523 break;
524
525 case 't': /* ssizet */
526 sz = sizeof(ssizet);
527 rsz = rtsize;
528 al = talign;
529 ral = rtalign;
530 break;
531
532 case 'd': /* sector */
533 sz = sizeof(sector);
534 rsz = rdsize;
535 al = dalign;
536 ral = rdalign;
537 break;
538
539 case 'e': /* eindex */
540 sz = sizeof(eindex);
541 rsz = resize;
542 al = ealign;
543 ral = realign;
544 break;
545
546 case 'p': /* pointer */
547 sz = sizeof(char*);
548 rsz = rpsize;
549 al = palign;
550 ral = rpalign;
551 break;
552
553 case 'x': /* hte */
554 size = ALGN(size, zalign);
555 size = ALGN(size, palign);
556 size += sizeof(char*);
557 size = ALGN(size, palign);
558 size += sizeof(char*);
559 size = ALGN(size, zalign);
560 rsize = ALGN(rsize, rzalign);
561 rsize = ALGN(rsize, rpalign);
562 rsize += rpsize;
563 rsize = ALGN(rsize, rpalign);
564 rsize += rpsize;
565 rsize = ALGN(rsize, rzalign);
566 align = ALGN(align, palign);
567 ralign = ALGN(ralign, rpalign);
568 continue;
569
570 case '[': /* struct */
571 sz = conf_dsize(p);
572 al = (sz >> 8) & 0xff;
573 rsz = (sz >> 16) & 0xff;
574 ral = sz >> 24;
575 sz &= 0xff;
576 p = strchr(p, ']') + 1;
577 break;
578
579 case ']':
580 case '\0': /* end of layout */
581 if (p != layout + 2) {
582 /* a stuct and not an array element */
583 align = ALGN(align, zalign);
584 ralign = ALGN(ralign, rzalign);
585 }
586 return ALGN(rsize, ralign) |
587 (ralign << 8) |
588 (ALGN(size, align) << 16) |
589 (align << 24);
590 }
591
592 size = ALGN(size, al) + sz;
593 rsize = ALGN(rsize, ral) + rsz;
594 align = ALGN(align, al);
595 ralign = ALGN(ralign, ral);
596 }
597 }
598
599 /*
600 * NAME: conf_dconv()
601 * DESCRIPTION: convert structs from snapshot format
602 */
conf_dconv(char * buf,char * rbuf,char * layout,Uint n)603 Uint conf_dconv(char *buf, char *rbuf, char *layout, Uint n)
604 {
605 Uint i, ri, j, size, rsize;
606 char *p;
607
608 rsize = conf_dsize(layout);
609 size = (rsize >> 16) & 0xff;
610 rsize &= 0xff;
611 while (n > 0) {
612 i = ri = 0;
613 for (p = layout; *p != '\0' && *p != ']'; p++) {
614 switch (*p) {
615 case 'c':
616 i = ALGN(i, calign);
617 ri = ALGN(ri, rcalign);
618 buf[i] = rbuf[ri];
619 i += sizeof(char);
620 ri += sizeof(char);
621 break;
622
623 case 's':
624 i = ALGN(i, salign);
625 ri = ALGN(ri, rsalign);
626 buf[i + s0] = rbuf[ri + rs0];
627 buf[i + s1] = rbuf[ri + rs1];
628 i += sizeof(short);
629 ri += sizeof(short);
630 break;
631
632 case 'u':
633 i = ALGN(i, ualign);
634 ri = ALGN(ri, rualign);
635 if (sizeof(uindex) == rusize) {
636 if (sizeof(uindex) == sizeof(short)) {
637 buf[i + s0] = rbuf[ri + rs0];
638 buf[i + s1] = rbuf[ri + rs1];
639 } else {
640 buf[i + i0] = rbuf[ri + ri0];
641 buf[i + i1] = rbuf[ri + ri1];
642 buf[i + i2] = rbuf[ri + ri2];
643 buf[i + i3] = rbuf[ri + ri3];
644 }
645 } else {
646 j = (UCHAR(rbuf[ri + rs0] & rbuf[ri + rs1]) == 0xff) ?
647 -1 : 0;
648 buf[i + i0] = j;
649 buf[i + i1] = j;
650 buf[i + i2] = rbuf[ri + rs0];
651 buf[i + i3] = rbuf[ri + rs1];
652 }
653 i += sizeof(uindex);
654 ri += rusize;
655 break;
656
657 case 'i':
658 i = ALGN(i, ialign);
659 ri = ALGN(ri, rialign);
660 buf[i + i0] = rbuf[ri + ri0];
661 buf[i + i1] = rbuf[ri + ri1];
662 buf[i + i2] = rbuf[ri + ri2];
663 buf[i + i3] = rbuf[ri + ri3];
664 i += sizeof(Int);
665 ri += sizeof(Int);
666 break;
667
668 case 't':
669 i = ALGN(i, talign);
670 ri = ALGN(ri, rtalign);
671 if (sizeof(ssizet) == rtsize) {
672 if (sizeof(ssizet) == sizeof(short)) {
673 buf[i + s0] = rbuf[ri + rs0];
674 buf[i + s1] = rbuf[ri + rs1];
675 } else {
676 buf[i + i0] = rbuf[ri + ri0];
677 buf[i + i1] = rbuf[ri + ri1];
678 buf[i + i2] = rbuf[ri + ri2];
679 buf[i + i3] = rbuf[ri + ri3];
680 }
681 } else {
682 buf[i + i0] = 0;
683 buf[i + i1] = 0;
684 buf[i + i2] = rbuf[ri + rs0];
685 buf[i + i3] = rbuf[ri + rs1];
686 }
687 i += sizeof(ssizet);
688 ri += rtsize;
689 break;
690
691 case 'd':
692 i = ALGN(i, dalign);
693 ri = ALGN(ri, rdalign);
694 if (sizeof(sector) == rdsize) {
695 if (sizeof(sector) == sizeof(short)) {
696 buf[i + s0] = rbuf[ri + rs0];
697 buf[i + s1] = rbuf[ri + rs1];
698 } else {
699 buf[i + i0] = rbuf[ri + ri0];
700 buf[i + i1] = rbuf[ri + ri1];
701 buf[i + i2] = rbuf[ri + ri2];
702 buf[i + i3] = rbuf[ri + ri3];
703 }
704 } else {
705 j = (UCHAR(rbuf[ri + rs0] & rbuf[ri + rs1]) == 0xff) ?
706 -1 : 0;
707 buf[i + i0] = j;
708 buf[i + i1] = j;
709 buf[i + i2] = rbuf[ri + rs0];
710 buf[i + i3] = rbuf[ri + rs1];
711 }
712 i += sizeof(sector);
713 ri += rdsize;
714 break;
715
716 case 'e':
717 i = ALGN(i, ealign);
718 ri = ALGN(ri, realign);
719 i += sizeof(eindex);
720 ri += resize;
721 break;
722
723 case 'p':
724 i = ALGN(i, palign);
725 ri = ALGN(ri, rpalign);
726 for (j = sizeof(char*); j > 0; --j) {
727 buf[i++] = 0;
728 }
729 ri += rpsize;
730 break;
731
732 case '[':
733 j = conf_dsize(++p);
734 i = ALGN(i, j >> 24);
735 ri = ALGN(ri, (j >> 8) & 0xff);
736 j = conf_dconv(buf + i, rbuf + ri, p, (Uint) 1);
737 i += (j >> 16) & 0xff;
738 ri += j & 0xff;
739 p = strchr(p, ']');
740 break;
741
742 case 'x':
743 i = ALGN(i, zalign);
744 i = ALGN(i, palign);
745 for (j = sizeof(char*); j > 0; --j) {
746 buf[i++] = 0;
747 }
748 i = ALGN(i, palign);
749 for (j = sizeof(char*); j > 0; --j) {
750 buf[i++] = 0;
751 }
752 ri = ALGN(ri, rzalign);
753 ri = ALGN(ri, rpalign);
754 ri += rpsize;
755 ri = ALGN(ri, rpalign);
756 for (j = rpsize; j > 0; --j) {
757 if (rbuf[ri] != 0) {
758 buf[i - 1] = 1;
759 break;
760 }
761 ri++;
762 }
763 ri += j;
764 i = ALGN(i, zalign);
765 ri = ALGN(ri, rzalign);
766 break;
767 }
768 }
769
770 buf += size;
771 rbuf += rsize;
772 --n;
773 }
774
775 return (size << 16) | rsize;
776 }
777
778 /*
779 * NAME: conf->dread()
780 * DESCRIPTION: read from snapshot
781 */
conf_dread(int fd,char * buf,char * layout,Uint n)782 void conf_dread(int fd, char *buf, char *layout, Uint n)
783 {
784 char buffer[16384];
785 unsigned int i, size, rsize;
786 Uint tmp;
787
788 tmp = conf_dsize(layout);
789 size = (tmp >> 16) & 0xff;
790 rsize = tmp & 0xff;
791 while (n != 0) {
792 i = sizeof(buffer) / rsize;
793 if (i > n) {
794 i = n;
795 }
796 if (P_read(fd, buffer, i * rsize) != i * rsize) {
797 fatal("cannot read from snapshot");
798 }
799 conf_dconv(buf, buffer, layout, (Uint) i);
800 buf += size * i;
801 n -= i;
802 }
803 }
804
805
806 # define MAX_PORTS 32
807 # define MAX_STRINGS 32
808
809 static char *hotboot[MAX_STRINGS], *dirs[MAX_STRINGS], *modules[MAX_STRINGS];
810 static char *bhosts[MAX_PORTS], *thosts[MAX_PORTS];
811 static unsigned short bports[MAX_PORTS], tports[MAX_PORTS];
812 static int ntports, nbports;
813
814 /*
815 * NAME: conferr()
816 * DESCRIPTION: error during the configuration phase
817 */
conferr(char * err)818 static void conferr(char *err)
819 {
820 message("Config error, line %u: %s\012", tk_line(), err); /* LF */
821 }
822
823 /*
824 * NAME: config->config()
825 * DESCRIPTION: read config file
826 */
conf_config()827 static bool conf_config()
828 {
829 char buf[STRINGSZ];
830 char *p;
831 int h, l, m, c;
832 char **strs;
833 unsigned short *ports;
834
835 for (h = NR_OPTIONS; h > 0; ) {
836 conf[--h].set = FALSE;
837 }
838 memset(dirs, '\0', sizeof(dirs));
839 strs = (char **) NULL;
840
841 while ((c=pp_gettok()) != EOF) {
842 if (c != IDENTIFIER) {
843 conferr("option expected");
844 return FALSE;
845 }
846
847 l = 0;
848
849 h = NR_OPTIONS;
850
851 for (;;) {
852 c = strcmp(yytext, conf[m = (l + h) >> 1].name);
853 if (c == 0) {
854 break; /* found */
855 } else if (c < 0) {
856 h = m; /* search in lower half */
857 } else {
858 l = m + 1; /* search in upper half */
859 }
860 if (l >= h) {
861 conferr("unknown option");
862 return FALSE;
863 }
864 }
865
866 if (pp_gettok() != '=') {
867 conferr("'=' expected");
868 return FALSE;
869 }
870
871 if ((c=pp_gettok()) != conf[m].type) {
872 if (c != INT_CONST && c != STRING_CONST && c != '(') {
873 conferr("syntax error");
874 return FALSE;
875 } else if (conf[m].type != '[' || c != INT_CONST) {
876 if (conf[m].type == '[' && c == '(') {
877 c = '[';
878 } else {
879 conferr("bad value type");
880 return FALSE;
881 }
882 }
883 }
884
885 switch (c) {
886 case INT_CONST:
887 if (yylval.number < conf[m].low ||
888 (conf[m].high != 0 && yylval.number > conf[m].high)) {
889 conferr("int value out of range");
890 return FALSE;
891 }
892 switch (m) {
893 case BINARY_PORT:
894 bhosts[0] = (char *) NULL;
895 bports[0] = yylval.number;
896 nbports = 1;
897 break;
898
899 case TELNET_PORT:
900 thosts[0] = (char *) NULL;
901 tports[0] = yylval.number;
902 ntports = 1;
903 break;
904
905 default:
906 conf[m].u.num = yylval.number;
907 break;
908 }
909 break;
910
911 case STRING_CONST:
912 p = (conf[m].resolv) ? path_resolve(buf, yytext) : yytext;
913 l = strlen(p);
914 if (l >= STRINGSZ) {
915 l = STRINGSZ - 1;
916 p[l] = '\0';
917 }
918 m_static();
919 conf[m].u.str = strcpy(ALLOC(char, l + 1), p);
920 m_dynamic();
921 break;
922
923 case '(':
924 if (pp_gettok() != '{') {
925 conferr("'{' expected");
926 return FALSE;
927 }
928 l = 0;
929 switch (m) {
930 case HOTBOOT: strs = hotboot; break;
931 case INCLUDE_DIRS: strs = dirs; break;
932 case MODULES: strs = modules; break;
933 }
934 for (;;) {
935 if (pp_gettok() != STRING_CONST) {
936 conferr("string expected");
937 return FALSE;
938 }
939 if (l == MAX_STRINGS - 1) {
940 conferr("array too large");
941 return FALSE;
942 }
943 m_static();
944 strs[l] = strcpy(ALLOC(char, strlen(yytext) + 1), yytext);
945 l++;
946 m_dynamic();
947 if ((c=pp_gettok()) == '}') {
948 break;
949 }
950 if (c != ',') {
951 conferr("',' expected");
952 return FALSE;
953 }
954 }
955 if (pp_gettok() != ')') {
956 conferr("')' expected");
957 return FALSE;
958 }
959 strs[l] = (char *) NULL;
960 break;
961
962 case '[':
963 if (pp_gettok() != '[') {
964 conferr("'[' expected");
965 return FALSE;
966 }
967 l = 0;
968 if ((c=pp_gettok()) != ']') {
969 if (m == BINARY_PORT) {
970 strs = bhosts;
971 ports = bports;
972 } else {
973 strs = thosts;
974 ports = tports;
975 }
976 for (;;) {
977 if (l == MAX_PORTS) {
978 conferr("too many ports");
979 return FALSE;
980 }
981 if (c != STRING_CONST) {
982 conferr("string expected");
983 return FALSE;
984 }
985 if (strcmp(yytext, "*") == 0) {
986 strs[l] = (char *) NULL;
987 } else {
988 m_static();
989 strs[l] = strcpy(ALLOC(char, strlen(yytext) + 1),
990 yytext);
991 m_dynamic();
992 }
993 if (pp_gettok() != ':') {
994 conferr("':' expected");
995 return FALSE;
996 }
997 if (pp_gettok() != INT_CONST) {
998 conferr("integer expected");
999 return FALSE;
1000 }
1001 if (yylval.number <= 0 || yylval.number > USHRT_MAX) {
1002 conferr("int value out of range");
1003 return FALSE;
1004 }
1005 ports[l++] = yylval.number;
1006 if ((c=pp_gettok()) == ']') {
1007 break;
1008 }
1009 if (c != ',') {
1010 conferr("',' expected");
1011 return FALSE;
1012 }
1013 c = pp_gettok();
1014 }
1015 }
1016 if (pp_gettok() != ')') {
1017 conferr("')' expected");
1018 return FALSE;
1019 }
1020 if (m == TELNET_PORT) {
1021 ntports = l;
1022 } else {
1023 nbports = l;
1024 }
1025 break;
1026 }
1027 conf[m].set = TRUE;
1028 if (pp_gettok() != ';') {
1029 conferr("';' expected");
1030 return FALSE;
1031 }
1032 }
1033
1034 for (l = 0; l < NR_OPTIONS; l++) {
1035 if (!conf[l].set && l != HOTBOOT && l != MODULES) {
1036 char buffer[64];
1037
1038 #ifndef NETWORK_EXTENSIONS
1039 /* don't complain about the ports option not being
1040 specified if the network extensions are disabled */
1041 if (l == PORTS) {
1042 continue;
1043 }
1044 #endif
1045 sprintf(buffer, "unspecified option %s", conf[l].name);
1046 conferr(buffer);
1047 return FALSE;
1048 }
1049 }
1050
1051 return TRUE;
1052 }
1053
1054 static char *fname; /* file name */
1055 static int fd; /* file descriptor */
1056 static char *obuf; /* output buffer */
1057 static unsigned int bufsz; /* buffer size */
1058
1059 /*
1060 * NAME: config->open()
1061 * DESCRIPTION: create a new file
1062 */
copen(char * file)1063 static bool copen(char *file)
1064 {
1065 char fname[STRINGSZ];
1066
1067 path_resolve(fname, file);
1068 if ((fd=P_open(fname, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, 0644)) < 0) {
1069 message("Config error: cannot create \"/%s\"\012", fname); /* LF */
1070 return FALSE;
1071 }
1072 bufsz = 0;
1073
1074 return TRUE;
1075 }
1076
1077 /*
1078 * NAME: config->put()
1079 * DESCRIPTION: write a string to a file
1080 */
cputs(char * str)1081 static void cputs(char *str)
1082 {
1083 unsigned int len, chunk;
1084
1085 len = strlen(str);
1086 while (bufsz + len > BUF_SIZE) {
1087 chunk = BUF_SIZE - bufsz;
1088 memcpy(obuf + bufsz, str, chunk);
1089 (void) P_write(fd, obuf, BUF_SIZE);
1090 str += chunk;
1091 len -= chunk;
1092 bufsz = 0;
1093 }
1094 if (len > 0) {
1095 memcpy(obuf + bufsz, str, len);
1096 bufsz += len;
1097 }
1098 }
1099
1100 /*
1101 * NAME: config->close()
1102 * DESCRIPTION: close a file
1103 */
cclose()1104 static bool cclose()
1105 {
1106 if (bufsz > 0 && P_write(fd, obuf, bufsz) != bufsz) {
1107 message("Config error: cannot write \"/%s\"\012", fname); /* LF */
1108 P_close(fd);
1109 return FALSE;
1110 }
1111 P_close(fd);
1112
1113 return TRUE;
1114 }
1115
1116 /*
1117 * NAME: config->includes()
1118 * DESCRIPTION: create include files
1119 */
conf_includes()1120 static bool conf_includes()
1121 {
1122 char buf[BUF_SIZE], buffer[STRINGSZ];
1123 register int i;
1124 register char *p;
1125
1126 /* create status.h file */
1127 obuf = buf;
1128 sprintf(buffer, "%s/status.h", dirs[0]);
1129 if (!copen(buffer)) {
1130 return FALSE;
1131 }
1132 cputs("/*\012 * This file defines the fields of the array returned ");
1133 cputs("by the\012 * status() kfun. It is automatically generated ");
1134 cputs("by DGD on startup.\012 */\012\012");
1135 cputs("# define ST_VERSION\t0\t/* driver version */\012");
1136 cputs("# define ST_STARTTIME\t1\t/* system start time */\012");
1137 cputs("# define ST_BOOTTIME\t2\t/* system reboot time */\012");
1138 cputs("# define ST_UPTIME\t3\t/* system virtual uptime */\012");
1139 cputs("# define ST_SWAPSIZE\t4\t/* # sectors on swap device */\012");
1140 cputs("# define ST_SWAPUSED\t5\t/* # sectors in use */\012");
1141 cputs("# define ST_SECTORSIZE\t6\t/* size of swap sector */\012");
1142 cputs("# define ST_SWAPRATE1\t7\t/* # objects swapped out last minute */\012");
1143 cputs("# define ST_SWAPRATE5\t8\t/* # objects swapped out last five minutes */\012");
1144 cputs("# define ST_SMEMSIZE\t9\t/* static memory allocated */\012");
1145 cputs("# define ST_SMEMUSED\t10\t/* static memory in use */\012");
1146 cputs("# define ST_DMEMSIZE\t11\t/* dynamic memory allocated */\012");
1147 cputs("# define ST_DMEMUSED\t12\t/* dynamic memory in use */\012");
1148 cputs("# define ST_OTABSIZE\t13\t/* object table size */\012");
1149 cputs("# define ST_NOBJECTS\t14\t/* # objects in use */\012");
1150 cputs("# define ST_COTABSIZE\t15\t/* callout table size */\012");
1151 cputs("# define ST_NCOSHORT\t16\t/* # short-term callouts */\012");
1152 cputs("# define ST_NCOLONG\t17\t/* # long-term & millisecond callouts */\012");
1153 cputs("# define ST_UTABSIZE\t18\t/* user table size */\012");
1154 cputs("# define ST_ETABSIZE\t19\t/* editor table size */\012");
1155 cputs("# define ST_STRSIZE\t20\t/* max string size */\012");
1156 cputs("# define ST_ARRAYSIZE\t21\t/* max array/mapping size */\012");
1157 cputs("# define ST_STACKDEPTH\t22\t/* remaining stack depth */\012");
1158 cputs("# define ST_TICKS\t23\t/* remaining ticks */\012");
1159 cputs("# define ST_PRECOMPILED\t24\t/* precompiled objects */\012");
1160 cputs("# define ST_TELNETPORTS\t25\t/* telnet ports */\012");
1161 cputs("# define ST_BINARYPORTS\t26\t/* binary ports */\012");
1162
1163 cputs("\012# define O_COMPILETIME\t0\t/* time of compilation */\012");
1164 cputs("# define O_PROGSIZE\t1\t/* program size of object */\012");
1165 cputs("# define O_DATASIZE\t2\t/* # variables in object */\012");
1166 cputs("# define O_NSECTORS\t3\t/* # sectors used by object */\012");
1167 cputs("# define O_CALLOUTS\t4\t/* callouts in object */\012");
1168 cputs("# define O_INDEX\t5\t/* unique ID for master object */\012");
1169 cputs("# define O_UNDEFINED\t6\t/* undefined functions */\012");
1170
1171 cputs("\012# define CO_HANDLE\t0\t/* callout handle */\012");
1172 cputs("# define CO_FUNCTION\t1\t/* function name */\012");
1173 cputs("# define CO_DELAY\t2\t/* delay */\012");
1174 cputs("# define CO_FIRSTXARG\t3\t/* first extra argument */\012");
1175 if (!cclose()) {
1176 return FALSE;
1177 }
1178
1179 /* create type.h file */
1180 sprintf(buffer, "%s/type.h", dirs[0]);
1181 if (!copen(buffer)) {
1182 return FALSE;
1183 }
1184 cputs("/*\012 * This file gives definitions for the value returned ");
1185 cputs("by the\012 * typeof() kfun. It is automatically generated ");
1186 cputs("by DGD on startup.\012 */\012\012");
1187 sprintf(buffer, "# define T_NIL\t\t%d\012", T_NIL);
1188 cputs(buffer);
1189 sprintf(buffer, "# define T_INT\t\t%d\012", T_INT);
1190 cputs(buffer);
1191 sprintf(buffer, "# define T_FLOAT\t%d\012", T_FLOAT);
1192 cputs(buffer);
1193 sprintf(buffer, "# define T_STRING\t%d\012", T_STRING);
1194 cputs(buffer);
1195 sprintf(buffer, "# define T_OBJECT\t%d\012", T_OBJECT);
1196 cputs(buffer);
1197 sprintf(buffer, "# define T_ARRAY\t%d\012", T_ARRAY);
1198 cputs(buffer);
1199 sprintf(buffer, "# define T_MAPPING\t%d\012", T_MAPPING);
1200 cputs(buffer);
1201 if (!cclose()) {
1202 return FALSE;
1203 }
1204
1205 /* create limits.h file */
1206 sprintf(buffer, "%s/limits.h", dirs[0]);
1207 if (!copen(buffer)) {
1208 return FALSE;
1209 }
1210 cputs("/*\012 * This file defines some basic sizes of datatypes and ");
1211 cputs("resources.\012 * It is automatically generated by DGD on ");
1212 cputs("startup.\012 */\012\012");
1213 cputs("# define CHAR_BIT\t\t8\t\t/* # bits in character */\012");
1214 cputs("# define CHAR_MIN\t\t0\t\t/* min character value */\012");
1215 cputs("# define CHAR_MAX\t\t255\t\t/* max character value */\012\012");
1216 cputs("# define INT_MIN\t\t0x80000000\t/* -2147483648 */\012");
1217 cputs("# define INT_MAX\t\t2147483647\t/* max integer value */\012\012");
1218 sprintf(buffer, "# define MAX_STRING_SIZE\t%u\t\t/* max string size (obsolete) */\012",
1219 MAX_STRLEN);
1220 cputs(buffer);
1221 if (!cclose()) {
1222 return FALSE;
1223 }
1224
1225 /* create float.h file */
1226 sprintf(buffer, "%s/float.h", dirs[0]);
1227 if (!copen(buffer)) {
1228 return FALSE;
1229 }
1230 cputs("/*\012 * This file describes the floating point type. It is ");
1231 cputs("automatically\012 * generated by DGD on startup.\012 */\012\012");
1232 cputs("# define FLT_RADIX\t2\t\t\t/* binary */\012");
1233 cputs("# define FLT_ROUNDS\t1\t\t\t/* round to nearest */\012");
1234 cputs("# define FLT_EPSILON\t7.2759576142E-12\t/* smallest x: 1.0 + x != 1.0 */\012");
1235 cputs("# define FLT_DIG\t11\t\t\t/* decimal digits of precision*/\012");
1236 cputs("# define FLT_MANT_DIG\t36\t\t\t/* binary digits of precision */\012");
1237 cputs("# define FLT_MIN\t2.22507385851E-308\t/* positive minimum */\012");
1238 cputs("# define FLT_MIN_EXP\t(-1021)\t\t\t/* minimum binary exponent */\012");
1239 cputs("# define FLT_MIN_10_EXP\t(-307)\t\t\t/* minimum decimal exponent */\012");
1240 cputs("# define FLT_MAX\t1.79769313485E+308\t/* positive maximum */\012");
1241 cputs("# define FLT_MAX_EXP\t1024\t\t\t/* maximum binary exponent */\012");
1242 cputs("# define FLT_MAX_10_EXP\t308\t\t\t/* maximum decimal exponent */\012");
1243 if (!cclose()) {
1244 return FALSE;
1245 }
1246
1247 /* create trace.h file */
1248 sprintf(buffer, "%s/trace.h", dirs[0]);
1249 if (!copen(buffer)) {
1250 return FALSE;
1251 }
1252 cputs("/*\012 * This file describes the fields of the array returned for ");
1253 cputs("every stack\012 * frame by the call_trace() function. It is ");
1254 cputs("automatically generated by DGD\012 * on startup.\012 */\012\012");
1255 cputs("# define TRACE_OBJNAME\t0\t/* name of the object */\012");
1256 cputs("# define TRACE_PROGNAME\t1\t/* name of the object the function is in */\012");
1257 cputs("# define TRACE_FUNCTION\t2\t/* function name */\012");
1258 cputs("# define TRACE_LINE\t3\t/* line number */\012");
1259 cputs("# define TRACE_EXTERNAL\t4\t/* external call flag */\012");
1260 cputs("# define TRACE_FIRSTARG\t5\t/* first argument to function */\012");
1261 if (!cclose()) {
1262 return FALSE;
1263 }
1264
1265 /* create kfun.h file */
1266 sprintf(buffer, "%s/kfun.h", dirs[0]);
1267 if (!copen(buffer)) {
1268 return FALSE;
1269 }
1270 cputs("/*\012 * This file defines the version of each supported kfun. ");
1271 cputs("It is automatically\012 * generated by DGD on ");
1272 cputs("startup.\012 */\012\012");
1273 for (i = KF_BUILTINS; i < nkfun; i++) {
1274 if (!isdigit(kftab[i].name[0])) {
1275 sprintf(buffer, "# define kf_%s\t\t%d\012", kftab[i].name,
1276 kftab[i].version);
1277 for (p = buffer + 9; *p != '\0'; p++) {
1278 if (*p == '.') {
1279 *p = '_';
1280 } else {
1281 *p = toupper(*p);
1282 }
1283 }
1284 cputs(buffer);
1285 }
1286 }
1287 cputs("\012\012/*\012 * Supported ciphers and hashing algorithms.\012 */");
1288 cputs("\012\012# define ENCRYPT_CIPHERS\t");
1289 for (i = 0; ; ) {
1290 sprintf(buffer, "\"%s\"", kfenc[i].name);
1291 cputs(buffer);
1292 if (++i == ne) {
1293 break;
1294 }
1295 cputs(", ");
1296 }
1297 cputs("\012# define DECRYPT_CIPHERS\t");
1298 for (i = 0; ; ) {
1299 sprintf(buffer, "\"%s\"", kfdec[i].name);
1300 cputs(buffer);
1301 if (++i == nd) {
1302 break;
1303 }
1304 cputs(", ");
1305 }
1306 cputs("\012# define HASH_ALGORITHMS\t");
1307 for (i = 0; ; ) {
1308 sprintf(buffer, "\"%s\"", kfhsh[i].name);
1309 cputs(buffer);
1310 if (++i == nh) {
1311 break;
1312 }
1313 cputs(", ");
1314 }
1315 cputs("\012");
1316
1317 return cclose();
1318 }
1319
1320
1321 extern bool ext_dgd (char*);
1322
1323 /*
1324 * NAME: config->init()
1325 * DESCRIPTION: initialize the driver
1326 */
conf_init(char * configfile,char * snapshot,char * snapshot2,char * module,sector * fragment)1327 bool conf_init(char *configfile, char *snapshot, char *snapshot2, char *module,
1328 sector *fragment)
1329 {
1330 char buf[STRINGSZ];
1331 int fd, fd2, i;
1332 bool init;
1333
1334 fd = fd2 = -1;
1335
1336 /*
1337 * process config file
1338 */
1339 if (!pp_init(path_native(buf, configfile), (char **) NULL, (string **) NULL,
1340 0, 0)) {
1341 message("Config error: cannot open config file\012"); /* LF */
1342 m_finish();
1343 return FALSE;
1344 }
1345 init = conf_config();
1346 pp_clear();
1347 m_purge();
1348 if (!init) {
1349 m_finish();
1350 return FALSE;
1351 }
1352
1353 /* make sure that we can handle the swapfile size */
1354 if( ((off_t) (sector) conf[SWAP_SIZE].u.num * (unsigned int) conf[SECTOR_SIZE].u.num) !=
1355 ((Uuint) (sector) conf[SWAP_SIZE].u.num * (unsigned int) conf[SECTOR_SIZE].u.num)
1356 ) {
1357 P_message("Config error: swap file size overflow.\012");
1358 m_finish();
1359 return FALSE;
1360 }
1361
1362 /* try to open the snapshot if one was provided */
1363 if (snapshot != (char *) NULL) {
1364 fd = P_open(path_native(buf, snapshot), O_RDONLY | O_BINARY, 0);
1365 if (fd < 0) {
1366 P_message("Config error: cannot open restore file\012"); /* LF */
1367 m_finish();
1368 return FALSE;
1369 }
1370 }
1371 if (snapshot2 != (char *) NULL) {
1372 fd2 = P_open(path_native(buf, snapshot2), O_RDONLY | O_BINARY, 0);
1373 if (fd2 < 0) {
1374 P_message("Config error: cannot open secondary restore file\012"); /* LF */
1375 if (snapshot != (char *) NULL) {
1376 P_close(fd);
1377 }
1378 m_finish();
1379 return FALSE;
1380 }
1381 }
1382
1383 m_static();
1384
1385 /* remove previously added kfuns */
1386 kf_clear();
1387
1388 for (i = 0; modules[i] != NULL; i++) {
1389 if (!ext_dgd(modules[i])) {
1390 message("Config error: cannot load runtime extension \"%s\"\012",
1391 modules[i]);
1392 if (snapshot2 != (char *) NULL) {
1393 P_close(fd2);
1394 }
1395 if (snapshot != (char *) NULL) {
1396 P_close(fd);
1397 }
1398 m_finish();
1399 return FALSE;
1400 }
1401 }
1402 if (module != (char *) NULL && !ext_dgd(module)) {
1403 message("Config error: cannot load runtime extension \"%s\"\012",/* LF*/
1404 module);
1405 if (snapshot2 != (char *) NULL) {
1406 P_close(fd2);
1407 }
1408 if (snapshot != (char *) NULL) {
1409 P_close(fd);
1410 }
1411 m_finish();
1412 return FALSE;
1413 }
1414
1415 /* initialize kfuns */
1416 kf_init();
1417
1418 /* change directory */
1419 if (P_chdir(path_native(buf, conf[DIRECTORY].u.str)) < 0) {
1420 message("Config error: bad base directory \"%s\"\012", /* LF */
1421 conf[DIRECTORY].u.str);
1422 if (snapshot2 != (char *) NULL) {
1423 P_close(fd2);
1424 }
1425 if (snapshot != (char *) NULL) {
1426 P_close(fd);
1427 }
1428 m_finish();
1429 return FALSE;
1430 }
1431
1432 /* initialize communications */
1433 if (!comm_init((int) conf[USERS].u.num,
1434 #ifdef NETWORK_EXTENSIONS
1435 (int) conf[PORTS].u.num,
1436 #endif
1437 thosts, bhosts,
1438 tports, bports,
1439 ntports, nbports)) {
1440 comm_clear();
1441 comm_finish();
1442 if (snapshot2 != (char *) NULL) {
1443 P_close(fd2);
1444 }
1445 if (snapshot != (char *) NULL) {
1446 P_close(fd);
1447 }
1448 m_finish();
1449 return FALSE;
1450 }
1451
1452 /* initialize arrays */
1453 arr_init((int) conf[ARRAY_SIZE].u.num);
1454
1455 /* initialize objects */
1456 o_init((uindex) conf[OBJECTS].u.num, (Uint) conf[DUMP_INTERVAL].u.num);
1457
1458 /* initialize swap device */
1459 if (!sw_init(conf[SWAP_FILE].u.str,
1460 (sector) conf[SWAP_SIZE].u.num,
1461 (sector) conf[CACHE_SIZE].u.num,
1462 (unsigned int) conf[SECTOR_SIZE].u.num)) {
1463 comm_clear();
1464 comm_finish();
1465 if (snapshot2 != (char *) NULL) {
1466 P_close(fd2);
1467 }
1468 if (snapshot != (char *) NULL) {
1469 P_close(fd);
1470 }
1471 m_finish();
1472 return FALSE;
1473 }
1474
1475 /* initialize swapped data handler */
1476 d_init();
1477 *fragment = conf[SWAP_FRAGMENT].u.num;
1478
1479 /* initalize editor */
1480 ed_init(conf[ED_TMPFILE].u.str,
1481 (int) conf[EDITORS].u.num);
1482
1483 /* initialize call_outs */
1484 if (!co_init((uindex) conf[CALL_OUTS].u.num)) {
1485 sw_finish();
1486 comm_clear();
1487 comm_finish();
1488 if (snapshot2 != (char *) NULL) {
1489 P_close(fd2);
1490 }
1491 if (snapshot != (char *) NULL) {
1492 P_close(fd);
1493 }
1494 m_finish();
1495 return FALSE;
1496 }
1497
1498 /* initialize interpreter */
1499 i_init(conf[CREATE].u.str, conf[TYPECHECKING].u.num == 2);
1500
1501 /* initialize compiler */
1502 c_init(conf[AUTO_OBJECT].u.str,
1503 conf[DRIVER_OBJECT].u.str,
1504 conf[INCLUDE_FILE].u.str,
1505 dirs,
1506 (int) conf[TYPECHECKING].u.num);
1507
1508 m_dynamic();
1509
1510 /* initialize memory manager */
1511 m_init((size_t) conf[STATIC_CHUNK].u.num,
1512 (size_t) conf[DYNAMIC_CHUNK].u.num);
1513
1514 /*
1515 * create include files
1516 */
1517 if (!conf_includes()) {
1518 sw_finish();
1519 comm_clear();
1520 comm_finish();
1521 if (snapshot2 != (char *) NULL) {
1522 P_close(fd2);
1523 }
1524 if (snapshot != (char *) NULL) {
1525 P_close(fd);
1526 }
1527 m_finish();
1528 return FALSE;
1529 }
1530
1531 /* load precompiled objects */
1532 if (!pc_preload(conf[AUTO_OBJECT].u.str, conf[DRIVER_OBJECT].u.str)) {
1533 sw_finish();
1534 comm_clear();
1535 comm_finish();
1536 if (snapshot2 != (char *) NULL) {
1537 P_close(fd2);
1538 }
1539 if (snapshot != (char *) NULL) {
1540 P_close(fd);
1541 }
1542 m_finish();
1543 return FALSE;
1544 }
1545
1546 /* initialize snapshot header */
1547 conf_dumpinit();
1548
1549 m_static(); /* allocate error context statically */
1550 ec_push((ec_ftn) NULL); /* guard error context */
1551 if (ec_push((ec_ftn) NULL)) {
1552 message((char *) NULL);
1553 endthread();
1554 message("Config error: initialization failed\012"); /* LF */
1555 ec_pop(); /* remove guard */
1556
1557 sw_finish();
1558 comm_clear();
1559 comm_finish();
1560 ed_finish();
1561 if (snapshot2 != (char *) NULL) {
1562 P_close(fd2);
1563 }
1564 if (snapshot != (char *) NULL) {
1565 P_close(fd);
1566 }
1567 m_finish();
1568 return FALSE;
1569 }
1570 m_dynamic();
1571 if (snapshot == (char *) NULL) {
1572 /* initialize mudlib */
1573 d_converted();
1574 if (ec_push((ec_ftn) errhandler)) {
1575 error((char *) NULL);
1576 }
1577 call_driver_object(cframe, "initialize", 0);
1578 ec_pop();
1579 } else {
1580 bool hotbooted;
1581
1582 /* restore snapshot */
1583 hotbooted = conf_restore(fd, fd2);
1584
1585 /* notify mudlib */
1586 if (ec_push((ec_ftn) errhandler)) {
1587 error((char *) NULL);
1588 }
1589 if (hotbooted) {
1590 PUSH_INTVAL(cframe, TRUE);
1591 call_driver_object(cframe, "restored", 1);
1592 } else {
1593 call_driver_object(cframe, "restored", 0);
1594 }
1595 ec_pop();
1596 }
1597 ec_pop();
1598 i_del_value(cframe->sp++);
1599 endthread();
1600 ec_pop(); /* remove guard */
1601
1602 #ifndef NETWORK_EXTENSIONS
1603 /* start accepting connections */
1604 comm_listen();
1605 #endif
1606 return TRUE;
1607 }
1608
1609 /*
1610 * NAME: config->base_dir()
1611 * DESCRIPTION: return the driver base directory
1612 */
conf_base_dir()1613 char *conf_base_dir()
1614 {
1615 return conf[DIRECTORY].u.str;
1616 }
1617
1618 /*
1619 * NAME: config->driver()
1620 * DESCRIPTION: return the driver object name
1621 */
conf_driver()1622 char *conf_driver()
1623 {
1624 return conf[DRIVER_OBJECT].u.str;
1625 }
1626
1627 /*
1628 * NAME: config->hotboot()
1629 * DESCRIPTION: return the hotboot executable
1630 */
conf_hotboot()1631 char **conf_hotboot()
1632 {
1633 return (conf[HOTBOOT].set) ? hotboot : (char **) NULL;
1634 }
1635
1636 /*
1637 * NAME: config->typechecking()
1638 * DESCRIPTION: return the global typechecking flag
1639 */
conf_typechecking()1640 int conf_typechecking()
1641 {
1642 return conf[TYPECHECKING].u.num;
1643 }
1644
1645 /*
1646 * NAME: config->array_size()
1647 * DESCRIPTION: return the maximum array size
1648 */
conf_array_size()1649 unsigned short conf_array_size()
1650 {
1651 return conf[ARRAY_SIZE].u.num;
1652 }
1653
1654 /*
1655 * NAME: putval()
1656 * DESCRIPTION: store a size_t as an integer or as a float approximation
1657 */
putval(value * v,size_t n)1658 static void putval(value *v, size_t n)
1659 {
1660 xfloat f1, f2;
1661
1662 if (n <= 0x7fffffffL) {
1663 PUT_INTVAL(v, n);
1664 } else {
1665 flt_itof((Int) (n >> 31), &f1);
1666 flt_ldexp(&f1, (Int) 31);
1667 flt_itof((Int) (n & 0x7fffffffL), &f2);
1668 flt_add(&f1, &f2);
1669 PUT_FLTVAL(v, f1);
1670 }
1671 }
1672
1673 /*
1674 * NAME: config->statusi()
1675 * DESCRIPTION: return resource usage information
1676 */
conf_statusi(frame * f,Int idx,value * v)1677 bool conf_statusi(frame *f, Int idx, value *v)
1678 {
1679 char *version;
1680 uindex ncoshort, ncolong;
1681 array *a;
1682 Uint t;
1683 int i;
1684
1685 switch (idx) {
1686 case 0: /* ST_VERSION */
1687 version = VERSION;
1688 PUT_STRVAL(v, str_new(version, (long) strlen(version)));
1689 break;
1690
1691 case 1: /* ST_STARTTIME */
1692 PUT_INTVAL(v, starttime);
1693 break;
1694
1695 case 2: /* ST_BOOTTIME */
1696 PUT_INTVAL(v, boottime);
1697 break;
1698
1699 case 3: /* ST_UPTIME */
1700 t = P_time();
1701 if (t < boottime) {
1702 t = boottime;
1703 }
1704 PUT_INTVAL(v, elapsed + t - boottime);
1705 break;
1706
1707 case 4: /* ST_SWAPSIZE */
1708 PUT_INTVAL(v, conf[SWAP_SIZE].u.num);
1709 break;
1710
1711 case 5: /* ST_SWAPUSED */
1712 PUT_INTVAL(v, sw_count());
1713 break;
1714
1715 case 6: /* ST_SECTORSIZE */
1716 PUT_INTVAL(v, conf[SECTOR_SIZE].u.num);
1717 break;
1718
1719 case 7: /* ST_SWAPRATE1 */
1720 PUT_INTVAL(v, co_swaprate1());
1721 break;
1722
1723 case 8: /* ST_SWAPRATE5 */
1724 PUT_INTVAL(v, co_swaprate5());
1725 break;
1726
1727 case 9: /* ST_SMEMSIZE */
1728 putval(v, m_info()->smemsize);
1729 break;
1730
1731 case 10: /* ST_SMEMUSED */
1732 putval(v, m_info()->smemused);
1733 break;
1734
1735 case 11: /* ST_DMEMSIZE */
1736 putval(v, m_info()->dmemsize);
1737 break;
1738
1739 case 12: /* ST_DMEMUSED */
1740 putval(v, m_info()->dmemused);
1741 break;
1742
1743 case 13: /* ST_OTABSIZE */
1744 PUT_INTVAL(v, conf[OBJECTS].u.num);
1745 break;
1746
1747 case 14: /* ST_NOBJECTS */
1748 PUT_INTVAL(v, o_count());
1749 break;
1750
1751 case 15: /* ST_COTABSIZE */
1752 PUT_INTVAL(v, conf[CALL_OUTS].u.num);
1753 break;
1754
1755 case 16: /* ST_NCOSHORT */
1756 co_info(&ncoshort, &ncolong);
1757 PUT_INTVAL(v, ncoshort);
1758 break;
1759
1760 case 17: /* ST_NCOLONG */
1761 co_info(&ncoshort, &ncolong);
1762 PUT_INTVAL(v, ncolong);
1763 break;
1764
1765 case 18: /* ST_UTABSIZE */
1766 PUT_INTVAL(v, conf[USERS].u.num);
1767 break;
1768
1769 case 19: /* ST_ETABSIZE */
1770 PUT_INTVAL(v, conf[EDITORS].u.num);
1771 break;
1772
1773 case 20: /* ST_STRSIZE */
1774 PUT_INTVAL(v, MAX_STRLEN);
1775 break;
1776
1777 case 21: /* ST_ARRAYSIZE */
1778 PUT_INTVAL(v, conf[ARRAY_SIZE].u.num);
1779 break;
1780
1781 case 22: /* ST_STACKDEPTH */
1782 PUT_INTVAL(v, i_get_depth(f));
1783 break;
1784
1785 case 23: /* ST_TICKS */
1786 PUT_INTVAL(v, i_get_ticks(f));
1787 break;
1788
1789 case 24: /* ST_PRECOMPILED */
1790 a = pc_list(f->data);
1791 if (a != (array *) NULL) {
1792 PUT_ARRVAL(v, a);
1793 } else {
1794 *v = nil_value;
1795 }
1796 break;
1797
1798 case 25: /* ST_TELNETPORTS */
1799 a = arr_new(f->data, (long) ntports);
1800 PUT_ARRVAL(v, a);
1801 for (i = 0, v = a->elts; i < ntports; i++, v++) {
1802 PUT_INTVAL(v, tports[i]);
1803 }
1804 break;
1805
1806 case 26: /* ST_BINARYPORTS */
1807 a = arr_new(f->data, (long) nbports);
1808 PUT_ARRVAL(v, a);
1809 for (i = 0, v = a->elts; i < nbports; i++, v++) {
1810 PUT_INTVAL(v, bports[i]);
1811 }
1812 break;
1813
1814 default:
1815 return FALSE;
1816 }
1817
1818 return TRUE;
1819 }
1820
1821 /*
1822 * NAME: config->status()
1823 * DESCRIPTION: return an array with information about resource usage
1824 */
conf_status(frame * f)1825 array *conf_status(frame *f)
1826 {
1827 value *v;
1828 Int i;
1829 array *a;
1830
1831 if (ec_push((ec_ftn) NULL)) {
1832 arr_ref(a);
1833 arr_del(a);
1834 error((char *) NULL);
1835 }
1836 a = arr_ext_new(f->data, 27L);
1837 for (i = 0, v = a->elts; i < 27; i++, v++) {
1838 conf_statusi(f, i, v);
1839 }
1840 ec_pop();
1841
1842 return a;
1843 }
1844
1845 /*
1846 * NAME: config->objecti()
1847 * DESCRIPTION: return object resource usage information
1848 */
conf_objecti(dataspace * data,object * obj,Int idx,value * v)1849 bool conf_objecti(dataspace *data, object *obj, Int idx, value *v)
1850 {
1851 control *ctrl;
1852 object *prog;
1853 array *a;
1854
1855 prog = (obj->flags & O_MASTER) ? obj : OBJR(obj->u_master);
1856 ctrl = (O_UPGRADING(prog)) ? OBJR(prog->prev)->ctrl : o_control(prog);
1857
1858 switch (idx) {
1859 case 0: /* O_COMPILETIME */
1860 PUT_INTVAL(v, ctrl->compiled);
1861 break;
1862
1863 case 1: /* O_PROGSIZE */
1864 PUT_INTVAL(v, d_get_progsize(ctrl));
1865 break;
1866
1867 case 2: /* O_DATASIZE */
1868 PUT_INTVAL(v, ctrl->nvariables);
1869 break;
1870
1871 case 3: /* O_NSECTORS */
1872 PUT_INTVAL(v, (O_HASDATA(obj)) ? o_dataspace(obj)->nsectors : 0);
1873 if (obj->flags & O_MASTER) {
1874 v->u.number += ctrl->nsectors;
1875 }
1876 break;
1877
1878 case 4: /* O_CALLOUTS */
1879 if (O_HASDATA(obj)) {
1880 a = d_list_callouts(data, o_dataspace(obj));
1881 if (a != (array *) NULL) {
1882 PUT_ARRVAL(v, a);
1883 } else {
1884 *v = nil_value;
1885 }
1886 } else {
1887 PUT_ARRVAL(v, arr_new(data, 0L));
1888 }
1889 break;
1890
1891 case 5: /* O_INDEX */
1892 PUT_INTVAL(v, (obj->flags & O_MASTER) ?
1893 (Uint) obj->index : obj->u_master);
1894 break;
1895
1896 case 6: /* O_UNDEFINED */
1897 if (ctrl->flags & CTRL_UNDEFINED) {
1898 PUT_MAPVAL(v, ctrl_undefined(data, ctrl));
1899 } else {
1900 *v = nil_value;
1901 }
1902 break;
1903
1904 default:
1905 return FALSE;
1906 }
1907
1908 return TRUE;
1909 }
1910
1911 /*
1912 * NAME: config->object()
1913 * DESCRIPTION: return resource usage of an object
1914 */
conf_object(dataspace * data,object * obj)1915 array *conf_object(dataspace *data, object *obj)
1916 {
1917 value *v;
1918 Int i;
1919 array *a;
1920
1921 a = arr_ext_new(data, 7L);
1922 if (ec_push((ec_ftn) NULL)) {
1923 arr_ref(a);
1924 arr_del(a);
1925 error((char *) NULL);
1926 }
1927 for (i = 0, v = a->elts; i < 7; i++, v++) {
1928 conf_objecti(data, obj, i, v);
1929 }
1930 ec_pop();
1931
1932 return a;
1933 }
1934
1935
1936 /*
1937 * NAME: strtoint()
1938 * DESCRIPTION: retrieve an Int from a string (utility function)
1939 */
strtoint(char ** str)1940 Int strtoint(char **str)
1941 {
1942 char *p;
1943 Int i;
1944 Int sign;
1945
1946 p = *str;
1947 if (*p == '-') {
1948 p++;
1949 sign = -1;
1950 } else {
1951 sign = 1;
1952 }
1953
1954 i = 0;
1955 while (isdigit(*p)) {
1956 if ((Uint) i > (Uint) 214748364L) {
1957 return 0;
1958 }
1959 i = i * 10 + *p++ - '0';
1960 if (i < 0 && ((Uint) i != (Uint) 0x80000000L || sign > 0)) {
1961 return 0;
1962 }
1963 }
1964
1965 *str = p;
1966 return sign * i;
1967 }
1968