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