ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/utils.C
Revision: 1.87
Committed: Sun Oct 11 01:35:53 2009 UTC (14 years, 7 months ago) by sf-marcmagus
Content type: text/plain
Branch: MAIN
Changes since 1.86: +22 -0 lines
Log Message:
Fix exploit where books inscribed or marking runes created by players could
contain special text such as "@match" or "@eval" which would allow them to
execute arbitrary code.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.68 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 pippijn 1.39 *
4 root 1.74 * Copyright (©) 2005,2006,2007,2008 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.57 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.39 *
8 root 1.68 * Deliantra is free software: you can redistribute it and/or modify
9 root 1.60 * it under the terms of the GNU General Public License as published by
10     * the Free Software Foundation, either version 3 of the License, or
11     * (at your option) any later version.
12 pippijn 1.39 *
13 root 1.60 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17 pippijn 1.39 *
18 root 1.60 * You should have received a copy of the GNU General Public License
19     * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 root 1.57 *
21 root 1.68 * The authors can be reached via e-mail to <support@deliantra.net>
22 pippijn 1.39 */
23 elmex 1.1
24     /*
25     * General convenience functions for crossfire.
26     */
27    
28 root 1.37 #include <cstdlib>
29     #include <sys/types.h>
30     #include <unistd.h>
31     #include <sys/time.h>
32     #include <time.h>
33     #include <signal.h>
34    
35 elmex 1.1 #include <global.h>
36     #include <material.h>
37 sf-marcmagus 1.87 #include <object.h>
38 elmex 1.1
39 root 1.79 #include <sys/time.h>
40     #include <sys/resource.h>
41    
42 root 1.4 #include <glib.h>
43    
44 root 1.63 refcnt_base::refcnt_t refcnt_dummy;
45 root 1.74 ssize_t slice_alloc;
46 root 1.77 rand_gen rndm, rmg_rndm;
47 root 1.40
48 root 1.42 void
49     tausworthe_random_generator::seed (uint32_t seed)
50 root 1.40 {
51 root 1.74 state [0] = seed * 69069U; if (state [0] < 2U) state [0] += 2U;
52     state [1] = state [0] * 69069U; if (state [0] < 8U) state [0] += 8U;
53     state [2] = state [1] * 69069U; if (state [0] < 16U) state [0] += 16U;
54     state [3] = state [2] * 69069U; if (state [0] < 128U) state [0] += 128U;
55 root 1.40
56     for (int i = 11; --i; )
57 root 1.84 next ();
58 root 1.40 }
59    
60     uint32_t
61     tausworthe_random_generator::next ()
62     {
63     state [0] = ((state [0] & 0xFFFFFFFEU) << 18U) ^ (((state [0] << 6U) ^ state [0]) >> 13U);
64     state [1] = ((state [1] & 0xFFFFFFF8U) << 2U) ^ (((state [1] << 2U) ^ state [1]) >> 27U);
65     state [2] = ((state [2] & 0xFFFFFFF0U) << 7U) ^ (((state [2] << 13U) ^ state [2]) >> 21U);
66     state [3] = ((state [3] & 0xFFFFFF80U) << 13U) ^ (((state [3] << 3U) ^ state [3]) >> 12U);
67    
68     return state [0] ^ state [1] ^ state [2] ^ state [3];
69     }
70    
71 root 1.84 template<class generator>
72 root 1.42 uint32_t
73 root 1.84 random_number_generator<generator>::get_range (uint32_t num)
74 root 1.42 {
75 root 1.84 return (this->next () * (uint64_t)num) >> 32U;
76 root 1.42 }
77    
78     // return a number within (min .. max)
79 root 1.84 template<class generator>
80 root 1.42 int
81 root 1.84 random_number_generator<generator>::get_range (int r_min, int r_max)
82 root 1.42 {
83 root 1.50 return r_min + get_range (max (r_max - r_min + 1, 0));
84 root 1.42 }
85    
86 root 1.84 template struct random_number_generator<tausworthe_random_generator>;
87     template struct random_number_generator<xorshift_random_generator>;
88    
89 elmex 1.1 /*
90     * The random functions here take luck into account when rolling random
91     * dice or numbers. This function has less of an impact the larger the
92     * difference becomes in the random numbers. IE, the effect is lessened
93     * on a 1-1000 roll, vs a 1-6 roll. This can be used by crafty programmers,
94     * to specifically disable luck in certain rolls, simply by making the
95     * numbers larger (ie, 1d1000 > 500 vs 1d6 > 3)
96     */
97    
98     /*
99     * Roll a random number between min and max. Uses op to determine luck,
100     * and if goodbad is non-zero, luck increases the roll, if zero, it decreases.
101     * Generally, op should be the player/caster/hitter requesting the roll,
102     * not the recipient (ie, the poor slob getting hit). [garbled 20010916]
103     */
104 root 1.9 int
105 root 1.41 random_roll (int r_min, int r_max, const object *op, int goodbad)
106 root 1.9 {
107 root 1.78 r_max = max (r_min, r_max);
108    
109 root 1.41 int base = r_max - r_min > 1 ? 20 : 50; /* d2 and d3 are corner cases */
110 elmex 1.1
111 root 1.41 if (op->type == PLAYER)
112 root 1.9 {
113 root 1.41 int luck = op->stats.luck;
114 elmex 1.1
115 root 1.41 if (rndm (base) < min (10, abs (luck)))
116     {
117     //TODO: take luck into account
118     }
119 elmex 1.1 }
120 root 1.41
121     return rndm (r_min, r_max);
122 elmex 1.1 }
123    
124     /*
125     * This is a 64 bit version of random_roll above. This is needed
126     * for exp loss calculations for players changing religions.
127     */
128 root 1.9 sint64
129 root 1.78 random_roll64 (sint64 r_min, sint64 r_max, const object *op, int goodbad)
130 root 1.9 {
131 root 1.78 sint64 omin = r_min;
132     sint64 range = max (0, r_max - r_min + 1);
133     int base = range > 2 ? 20 : 50; /* d2 and d3 are corner cases */
134 elmex 1.1
135 root 1.45 /*
136     * Make a call to get two 32 bit unsigned random numbers, and just to
137     * a little bitshifting.
138 root 1.9 */
139 root 1.55 sint64 ran = (sint64) rndm.next () ^ ((sint64) rndm.next () << 31);
140 root 1.9
141     if (op->type != PLAYER)
142 root 1.78 return ((ran % range) + r_min);
143 root 1.9
144 root 1.55 int luck = op->stats.luck;
145    
146 root 1.78 if (rndm (base) < min (10, abs (luck)))
147 root 1.9 {
148     /* we have a winner */
149     ((luck > 0) ? (luck = 1) : (luck = -1));
150 root 1.78 range -= luck;
151     if (range < 1)
152 root 1.9 return (omin); /*check again */
153 root 1.55
154 root 1.78 ((goodbad) ? (r_min += luck) : (range));
155 elmex 1.1
156 root 1.78 return (max (omin, min (r_max, (ran % range) + r_min)));
157 elmex 1.1 }
158 root 1.45
159 root 1.78 return ran % range + r_min;
160 elmex 1.1 }
161    
162     /*
163     * Roll a number of dice (2d3, 4d6). Uses op to determine luck,
164     * If goodbad is non-zero, luck increases the roll, if zero, it decreases.
165     * Generally, op should be the player/caster/hitter requesting the roll,
166     * not the recipient (ie, the poor slob getting hit).
167     * The args are num D size (ie 4d6) [garbled 20010916]
168     */
169 root 1.9 int
170     die_roll (int num, int size, const object *op, int goodbad)
171     {
172 root 1.55 int min, luck, total, i, gotlucky;
173 root 1.9
174 root 1.55 int diff = size;
175 root 1.9 min = 1;
176     luck = total = gotlucky = 0;
177 root 1.55 int base = diff > 2 ? 20 : 50; /* d2 and d3 are corner cases */
178    
179 root 1.9 if (size < 2 || diff < 1)
180     {
181     LOG (llevError, "Calling die_roll with num=%d size=%d\n", num, size);
182 root 1.55 return num; /* avoids a float exception */
183 root 1.9 }
184 elmex 1.1
185 root 1.9 if (op->type == PLAYER)
186     luck = op->stats.luck;
187    
188     for (i = 0; i < num; i++)
189     {
190 root 1.45 if (rndm (base) < MIN (10, abs (luck)) && !gotlucky)
191 root 1.9 {
192     /* we have a winner */
193     gotlucky++;
194     ((luck > 0) ? (luck = 1) : (luck = -1));
195     diff -= luck;
196     if (diff < 1)
197     return (num); /*check again */
198     ((goodbad) ? (min += luck) : (diff));
199 root 1.45 total += MAX (1, MIN (size, rndm (diff) + min));
200 root 1.9 }
201     else
202 root 1.45 total += rndm (size) + 1;
203 elmex 1.1 }
204 root 1.45
205     return total;
206 elmex 1.1 }
207    
208     /* convert materialname to materialtype_t */
209    
210 root 1.9 materialtype_t *
211 root 1.83 name_to_material (const shstr_cmp name)
212 elmex 1.1 {
213 root 1.83 for (materialtype_t *mt = materialt; mt; mt = mt->next)
214 root 1.47 if (name == mt->name)
215     return mt;
216 elmex 1.1
217 root 1.62 return 0;
218 elmex 1.1 }
219    
220     /* when doing transmutation of objects, we have to recheck the resistances,
221     * as some that did not apply previously, may apply now.
222     */
223 root 1.9 void
224     transmute_materialname (object *op, const object *change)
225 elmex 1.1 {
226 root 1.9 materialtype_t *mt;
227     int j;
228 elmex 1.1
229 root 1.83 if (!op->materialname)
230 root 1.9 return;
231 elmex 1.1
232 root 1.85 if (op->materialname != change->materialname)
233 root 1.9 return;
234    
235 root 1.26 if (!op->is_armor ())
236 root 1.9 return;
237    
238     mt = name_to_material (op->materialname);
239     if (!mt)
240     {
241 root 1.58 LOG (llevError, "archetype '%s>%s' uses nonexistent material '%s'\n", &op->arch->archname, &op->name, &op->materialname);
242 root 1.9 return;
243     }
244    
245     for (j = 0; j < NROFATTACKS; j++)
246     if (op->resist[j] == 0 && change->resist[j] != 0)
247     {
248     op->resist[j] += mt->mod[j];
249     if (op->resist[j] > 100)
250     op->resist[j] = 100;
251     if (op->resist[j] < -100)
252     op->resist[j] = -100;
253     }
254 elmex 1.1 }
255    
256     /* set the materialname and type for an item */
257 root 1.9 void
258     set_materialname (object *op, int difficulty, materialtype_t *nmt)
259 elmex 1.1 {
260 root 1.9 materialtype_t *mt, *lmt;
261    
262 root 1.83 if (!op->materialname)
263 root 1.9 return;
264 elmex 1.1
265 root 1.83 if (nmt)
266     lmt = nmt;
267     else
268 root 1.9 {
269 root 1.83 lmt = 0;
270 root 1.61
271 root 1.83 for (mt = materialt; mt; mt = mt->next)
272 root 1.61 if (op->materials & mt->material && rndm (1, 100) <= mt->chance &&
273     difficulty >= mt->difficulty && (op->magic >= mt->magic || mt->magic == 0))
274     {
275     lmt = mt;
276     if (!(op->is_weapon () || op->is_armor ()))
277 root 1.9 break;
278 root 1.61 }
279 root 1.9 }
280 elmex 1.1
281 root 1.83 if (lmt)
282 root 1.9 {
283 root 1.26 if (op->stats.dam && op->is_weapon ())
284 root 1.9 {
285     op->stats.dam += lmt->damage;
286     if (op->stats.dam < 1)
287     op->stats.dam = 1;
288     }
289 root 1.46
290 root 1.9 if (op->stats.sp && op->type == BOW)
291     op->stats.sp += lmt->sp;
292 root 1.26 if (op->stats.wc && op->is_weapon ())
293 root 1.9 op->stats.wc += lmt->wc;
294 root 1.26 if (op->is_armor ())
295 root 1.9 {
296     if (op->stats.ac)
297     op->stats.ac += lmt->ac;
298 root 1.61
299     for (int j = 0; j < NROFATTACKS; j++)
300 root 1.9 if (op->resist[j] != 0)
301     {
302     op->resist[j] += lmt->mod[j];
303     if (op->resist[j] > 100)
304     op->resist[j] = 100;
305     if (op->resist[j] < -100)
306     op->resist[j] = -100;
307     }
308     }
309 root 1.61
310 root 1.46 op->materialname = lmt->name;
311 root 1.9 /* dont make it unstackable if it doesn't need to be */
312 root 1.26 if (op->is_weapon () || op->is_armor ())
313 root 1.9 {
314     op->weight = (op->weight * lmt->weight) / 100;
315     op->value = (op->value * lmt->value) / 100;
316 root 1.2 }
317 elmex 1.1 }
318     }
319    
320     /*
321     * Strip out the media tags from a String.
322     * Warning the input string will contain the result string
323     */
324 root 1.9 void
325     strip_media_tag (char *message)
326     {
327     int in_tag = 0;
328     char *dest;
329     char *src;
330    
331     src = dest = message;
332     while (*src != '\0')
333     {
334     if (*src == '[')
335     {
336     in_tag = 1;
337     }
338     else if (in_tag && (*src == ']'))
339     in_tag = 0;
340     else if (!in_tag)
341     {
342     *dest = *src;
343     dest++;
344     }
345     src++;
346     }
347     *dest = '\0';
348     }
349    
350     const char *
351     strrstr (const char *haystack, const char *needle)
352     {
353     const char *lastneedle;
354    
355     lastneedle = NULL;
356     while ((haystack = strstr (haystack, needle)) != NULL)
357     {
358     lastneedle = haystack;
359     haystack++;
360 elmex 1.1 }
361 root 1.9 return lastneedle;
362    
363 elmex 1.1 }
364 root 1.9
365 elmex 1.1 #define EOL_SIZE (sizeof("\n")-1)
366 root 1.9 void
367     strip_endline (char *buf)
368     {
369     if (strlen (buf) < sizeof ("\n"))
370     {
371     return;
372 elmex 1.1 }
373 root 1.9 if (!strcmp (buf + strlen (buf) - EOL_SIZE, "\n"))
374     buf[strlen (buf) - EOL_SIZE] = '\0';
375 elmex 1.1 }
376    
377     /**
378     * Replace in string src all occurrences of key by replacement. The resulting
379     * string is put into result; at most resultsize characters (including the
380     * terminating null character) will be written to result.
381     */
382 root 1.9 void
383     replace (const char *src, const char *key, const char *replacement, char *result, size_t resultsize)
384 elmex 1.1 {
385 root 1.9 size_t resultlen;
386     size_t keylen;
387 elmex 1.1
388 root 1.9 /* special case to prevent infinite loop if key==replacement=="" */
389     if (strcmp (key, replacement) == 0)
390     {
391     snprintf (result, resultsize, "%s", src);
392     return;
393     }
394    
395     keylen = strlen (key);
396    
397     resultlen = 0;
398     while (*src != '\0' && resultlen + 1 < resultsize)
399     {
400     if (strncmp (src, key, keylen) == 0)
401 root 1.2 {
402 root 1.9 snprintf (result + resultlen, resultsize - resultlen, "%s", replacement);
403     resultlen += strlen (result + resultlen);
404     src += keylen;
405 root 1.2 }
406 root 1.9 else
407 root 1.2 {
408 root 1.9 result[resultlen++] = *src++;
409 root 1.2 }
410 root 1.9 }
411     result[resultlen] = '\0';
412 elmex 1.1 }
413    
414     /**
415     * Taking a string as an argument, mutate it into a string that looks like a list.
416     * a 'list' for the purposes here, is a string of items, seperated by commas, except
417     * for the last entry, which has an 'and' before it, and a full stop (period) after it.
418     * This function will also strip all trailing non alphanumeric characters.
419     * It does not insert an oxford comma.
420     */
421 root 1.9 void
422     make_list_like (char *input)
423     {
424     char *p, tmp[MAX_BUF];
425     int i;
426    
427     if (!input || strlen (input) > MAX_BUF - 5)
428 elmex 1.1 return;
429 root 1.9 /* bad stuff would happen if we continued here, the -5 is to make space for ' and ' */
430    
431     strncpy (tmp, input, MAX_BUF - 5);
432     /*trim all trailing commas, spaces etc. */
433     for (i = strlen (tmp); !isalnum (tmp[i]) && i >= 0; i--)
434     tmp[i] = '\0';
435 root 1.11
436 root 1.9 strcat (tmp, ".");
437    
438     p = strrchr (tmp, ',');
439     if (p)
440     {
441     *p = '\0';
442     strcpy (input, tmp);
443     p++;
444     strcat (input, " and");
445     strcat (input, p);
446     }
447     else
448     strcpy (input, tmp);
449 root 1.11
450 root 1.9 return;
451 elmex 1.1 }
452 root 1.3
453 sf-marcmagus 1.87 /******************************************************************************/
454    
455     /* Checks a player-provided string which will become the msg property of
456     * an object for dangerous input.
457     */
458     bool
459     msg_is_safe (const char *msg)
460     {
461     bool safe = true;
462    
463     /* Trying to cheat by getting data into the object */
464     if (!strncmp (msg, "endmsg", strlen ("endmsg")) || strstr (msg, "\nendmsg"))
465     safe = false;
466    
467     /* Trying to make the object talk, and potentially access arbitrary code */
468     if (object::msg_has_dialogue (msg))
469     safe = false;
470    
471     return safe;
472     }
473    
474 root 1.14 /////////////////////////////////////////////////////////////////////////////
475    
476 root 1.37 void
477     fork_abort (const char *msg)
478     {
479     if (!fork ())
480     {
481 root 1.80 signal (SIGINT , SIG_IGN);
482     signal (SIGTERM, SIG_IGN);
483     signal (SIGABRT, SIG_IGN);
484 root 1.79
485 root 1.81 signal (SIGSEGV, SIG_DFL);
486     signal (SIGBUS , SIG_DFL);
487     signal (SIGILL , SIG_DFL);
488     signal (SIGTRAP, SIG_DFL);
489    
490 root 1.52 // try to put corefiles into a subdirectory, if existing, to allow
491     // an administrator to reduce the I/O load.
492     chdir ("cores");
493 root 1.79
494     // try to detach us from as many external dependencies as possible
495     // as coredumping can take time by closing all fd's.
496     {
497     struct rlimit lim;
498    
499     if (getrlimit (RLIMIT_NOFILE, &lim))
500     lim.rlim_cur = 1024;
501    
502     for (int i = 0; i < lim.rlim_cur; ++i)
503     close (i);
504     }
505    
506 root 1.81 {
507     sigset_t empty;
508     sigemptyset (&empty);
509     sigprocmask (SIG_SETMASK, &empty, 0);
510     }
511    
512     // try to coredump with SIGTRAP
513     kill (getpid (), SIGTRAP);
514 root 1.37 abort ();
515     }
516    
517 root 1.38 LOG (llevError, "fork abort: %s\n", msg);
518 root 1.37 }
519 root 1.38
520 root 1.25 void *salloc_ (int n) throw (std::bad_alloc)
521 root 1.10 {
522 root 1.25 void *ptr = g_slice_alloc (n);
523 root 1.13
524 root 1.23 if (!ptr)
525 root 1.13 throw std::bad_alloc ();
526 root 1.4
527 root 1.74 slice_alloc += n;
528 root 1.23 return ptr;
529     }
530    
531 root 1.25 void *salloc_ (int n, void *src) throw (std::bad_alloc)
532 root 1.23 {
533 root 1.25 void *ptr = salloc_ (n);
534 root 1.23
535 root 1.24 if (src)
536 root 1.25 memcpy (ptr, src, n);
537 root 1.24 else
538 root 1.25 memset (ptr, 0, n);
539 root 1.23
540     return ptr;
541 root 1.3 }
542 root 1.11
543 root 1.69 /******************************************************************************/
544    
545 root 1.72 #if DEBUG_SALLOC
546 root 1.69
547 root 1.70 #define MAGIC 0xa1b2c35543deadLL
548 root 1.69
549     void *g_slice_alloc (unsigned long size)
550     {
551     unsigned long *p = (unsigned long *) (g_slice_alloc)(size + sizeof (unsigned long));
552     *p++ = size ^ MAGIC;
553     //fprintf (stderr, "g_slice_alloc %ld %p\n", size, p);//D
554     return (void *)p;
555     }
556    
557     void *g_slice_alloc0 (unsigned long size)
558     {
559     return memset (g_slice_alloc (size), 0, size);
560     }
561    
562     void g_slice_free1 (unsigned long size, void *ptr)
563     {
564 root 1.74 //fprintf (stderr, "g_slice_free %ld %p\n", size, ptr);//D
565 root 1.69 if (expect_true (ptr))
566     {
567     unsigned long *p = (unsigned long *)ptr;
568     unsigned long s = *--p ^ MAGIC;
569    
570 root 1.71 if (size != (unsigned long)(*p ^ MAGIC))
571 root 1.74 {
572     LOG (logBacktrace | llevError, "slice free size (%lx) doesn't match alloc size (%lx)\n", size, s);
573     abort ();
574     }
575 root 1.69
576     *p = MAGIC;
577    
578     (g_slice_free1)(s + sizeof (unsigned long), p);
579     }
580     }
581    
582     #endif
583    
584     /******************************************************************************/
585    
586 root 1.86 int
587     assign (char *dst, const char *src, int maxsize)
588 root 1.11 {
589     if (!src)
590     src = "";
591    
592     int len = strlen (src);
593    
594 root 1.86 if (len >= maxsize)
595 root 1.11 {
596 root 1.86 if (maxsize <= 4)
597 root 1.11 {
598 root 1.86 memset (dst, '.', maxsize - 2);
599     dst [maxsize - 1] = 0;
600 root 1.11 }
601     else
602     {
603 root 1.86 memcpy (dst, src, maxsize - 4);
604     memcpy (dst + maxsize - 4, "...", 4);
605 root 1.11 }
606 root 1.86
607     len = maxsize;
608 root 1.11 }
609     else
610 root 1.86 memcpy (dst, src, ++len);
611    
612     return len;
613 root 1.11 }
614    
615 root 1.65 const char *
616 root 1.51 format (const char *format, ...)
617     {
618 root 1.65 static dynbuf_text buf;
619 root 1.51
620 root 1.65 buf.clear ();
621 root 1.51
622 root 1.65 va_list ap;
623     va_start (ap, format);
624     buf.vprintf (format, ap);
625     va_end (ap);
626    
627     return buf;
628 root 1.51 }
629    
630 root 1.23 tstamp now ()
631     {
632     struct timeval tv;
633    
634     gettimeofday (&tv, 0);
635     return tstamp (tv.tv_sec) + tstamp (tv.tv_usec) * tstamp (1e-6);
636     }
637 root 1.17
638 root 1.32 int
639     similar_direction (int a, int b)
640     {
641     if (!a || !b)
642     return 0;
643    
644     int diff = (b - a) & 7;
645     return diff <= 1 || diff >= 7;
646     }
647    
648 root 1.48 /* crc32 0xdebb20e3 table and supplementary functions. */
649     extern const uint32_t crc_32_tab[256] =
650     {
651     0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL,
652     0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL,
653     0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL,
654     0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL,
655     0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL,
656     0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL,
657     0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL,
658     0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL,
659     0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL,
660     0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL,
661     0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL,
662     0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL,
663     0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL,
664     0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL,
665     0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL,
666     0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL,
667     0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL,
668     0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL,
669     0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL,
670     0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL,
671     0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL,
672     0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL,
673     0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL,
674     0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL,
675     0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL,
676     0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL,
677     0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL,
678     0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL,
679     0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL,
680     0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL,
681     0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL,
682     0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL,
683     0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL,
684     0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL,
685     0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL,
686     0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL,
687     0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL,
688     0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL,
689     0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL,
690     0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL,
691     0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL,
692     0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL,
693     0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL,
694     0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL,
695     0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL,
696     0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL,
697     0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL,
698     0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL,
699     0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL,
700     0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL,
701     0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL,
702     0x2d02ef8dL
703     };
704    
705 root 1.73 void thread::start (void *(*start_routine)(void *), void *arg)
706     {
707 root 1.75 pthread_attr_t attr;
708    
709     pthread_attr_init (&attr);
710     pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
711     pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN < sizeof (long) * 4096
712     ? sizeof (long) * 4096 : PTHREAD_STACK_MIN);
713     #ifdef PTHREAD_SCOPE_PROCESS
714     pthread_attr_setscope (&attr, PTHREAD_SCOPE_PROCESS);
715     #endif
716    
717 root 1.73 sigset_t fullsigset, oldsigset;
718     sigfillset (&fullsigset);
719    
720     pthread_sigmask (SIG_SETMASK, &fullsigset, &oldsigset);
721    
722 root 1.75 if (pthread_create (&id, &attr, start_routine, arg))
723 root 1.73 cleanup ("unable to create a new thread");
724    
725     pthread_sigmask (SIG_SETMASK, &oldsigset, 0);
726     }
727 root 1.75