1 /* unix_main.c -- Miscellaneous functions for Unix
2    Copyright (C) 1993, 1994 John Harper <john@dcs.warwick.ac.uk>
3    $Id$
4 
5    This file is part of Jade.
6 
7    Jade is free software; you can redistribute it and/or modify it
8    under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2, or (at your option)
10    any later version.
11 
12    Jade is distributed in the hope that it will be useful, but
13    WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16 
17    You should have received a copy of the GNU General Public License
18    along with Jade; see the file COPYING.	If not, write to
19    the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
20 
21 #define _GNU_SOURCE
22 
23 #include "repint.h"
24 
25 #include <string.h>
26 #include <stdlib.h>
27 #include <assert.h>
28 #include <limits.h>
29 #include <sys/stat.h>
30 #include <time.h>
31 #include <pwd.h>
32 #include <netdb.h>
33 #include <signal.h>
34 
35 #ifdef HAVE_FCNTL_H
36 # include <fcntl.h>
37 #endif
38 
39 #ifdef HAVE_SYS_TIME_H
40 # include <sys/time.h>
41 #endif
42 
43 #ifdef HAVE_UNISTD_H
44 # include <unistd.h>
45 #endif
46 
47 #ifdef HAVE_SYS_UTSNAME_H
48 # include <sys/utsname.h>
49 #endif
50 
51 #ifdef HAVE_STRERROR
52 # include <errno.h>
53 #else
54   extern int sys_nerr, errno;
55   extern char *sys_errlist[];
56 #endif
57 
58 #ifdef ENVIRON_UNDECLARED
59   extern char **environ;
60 #endif
61 
62 void (*rep_redisplay_fun)(void);
63 long (*rep_wait_for_input_fun)(void *inputs, unsigned long timeout_msecs);
64 int rep_input_timeout_secs = 1;
65 
66 
67 /* Support functions */
68 
69 #ifndef HAVE_STRERROR
70 DEFSTRING(unknown_err, "Unknown system error");
71 #endif
72 repv
rep_lookup_errno(void)73 rep_lookup_errno(void)
74 {
75 #ifdef HAVE_STRERROR
76     return rep_string_dup(strerror(errno));
77 #else
78     if(errno >= sys_nerr)
79         return rep_string_dup(sys_errlist[errno]);
80     else
81         return rep_VAL(&unknown_err);
82 #endif
83 }
84 
85 unsigned long
rep_getpid(void)86 rep_getpid (void)
87 {
88     return getpid ();
89 }
90 
91 unsigned long
rep_time(void)92 rep_time(void)
93 {
94     return time(0);
95 }
96 
97 rep_long_long
rep_utime(void)98 rep_utime (void)
99 {
100     rep_long_long t;
101 #ifdef HAVE_GETTIMEOFDAY
102     struct timeval time;
103     gettimeofday (&time, 0);
104     t = ((rep_long_long) time.tv_sec * 1000000) + time.tv_usec;
105 #else
106     t = (rep_long_long) rep_time () * 1000000;
107 #endif
108     return t;
109 }
110 
111 void
rep_sleep_for(long secs,long msecs)112 rep_sleep_for(long secs, long msecs)
113 {
114     struct timeval timeout;
115     timeout.tv_sec = secs + msecs / 1000;
116     timeout.tv_usec = (msecs % 1000) * 1000;
117     select(FD_SETSIZE, NULL, NULL, NULL, &timeout);
118 }
119 
120 repv
rep_user_login_name(void)121 rep_user_login_name(void)
122 {
123     /* Just look this up once, then use the saved copy.	 */
124     static repv user_login_name;
125     char *tmp;
126     if(user_login_name)
127 	return user_login_name;
128 
129     if(!(tmp = getlogin()))
130     {
131 	struct passwd *pwd;
132 	if(!(pwd = getpwuid(geteuid())))
133 	    return rep_NULL;
134 	tmp = pwd->pw_name;
135     }
136     user_login_name = rep_string_dup(tmp);
137     rep_mark_static(&user_login_name);
138     return user_login_name;
139 }
140 
141 repv
rep_user_full_name(void)142 rep_user_full_name(void)
143 {
144     struct passwd *pwd;
145     static repv user_full_name;
146     if(user_full_name)
147 	return user_full_name;
148 
149     if(!(pwd = getpwuid(geteuid())))
150 	return rep_NULL;
151 #ifndef FULL_NAME_TERMINATOR
152     user_full_name = rep_string_dup(pwd->pw_gecos);
153 #else
154     {
155 	char *end = strchr(pwd->pw_gecos, FULL_NAME_TERMINATOR);
156 	if(end)
157 	    user_full_name = rep_string_dupn(pwd->pw_gecos, end - pwd->pw_gecos);
158 	else
159 	    user_full_name = rep_string_dup(pwd->pw_gecos);
160     }
161 #endif
162     rep_mark_static(&user_full_name);
163     return user_full_name;
164 }
165 
166 DEFSTRING(no_home, "Can't find home directory");
167 repv
rep_user_home_directory(repv user)168 rep_user_home_directory(repv user)
169 {
170     static repv user_home_directory;
171     if(rep_NILP(user) && user_home_directory)
172 	return user_home_directory;
173     else
174     {
175 	repv dir;
176 	char *src = 0;
177 	int len;
178 
179 	if(rep_NILP(user))
180 	    src = getenv("HOME");
181 
182 	if(src == 0)
183 	{
184 	    struct passwd *pwd;
185 	    if(rep_NILP(user))
186 		pwd = getpwuid(geteuid());
187 	    else
188 		pwd = getpwnam(rep_STR(user));
189 
190 	    if(pwd == 0 || pwd->pw_dir == 0)
191 		return Fsignal(Qerror, rep_LIST_2(rep_VAL(&no_home), user));
192 
193 	    src = pwd->pw_dir;
194 	}
195 
196 	len = strlen(src);
197 	if(src[len] != '/')
198 	{
199 	    dir = rep_string_dupn(src, len + 1);
200 	    rep_STR(dir)[len] = '/';
201 	    rep_STR(dir)[len+1] = 0;
202 	}
203 	else
204 	    dir = rep_string_dup(src);
205 
206 	if(rep_NILP(user))
207 	{
208 	    user_home_directory = dir;
209 	    rep_mark_static(&user_home_directory);
210 	}
211 
212 	return dir;
213     }
214 }
215 
216 repv
rep_system_name(void)217 rep_system_name(void)
218 {
219     char buf[256];
220     struct hostent *h;
221 
222     static repv system_name;
223     if(system_name)
224 	return system_name;
225 
226 #ifdef HAVE_GETHOSTNAME
227     if(gethostname(buf, 256))
228 	return rep_NULL;
229 #else
230     {
231 	struct utsname uts;
232 	uname(&uts);
233 	strncpy(buf, uts.nodename, 256);
234     }
235 #endif
236     h = gethostbyname(buf);
237     if(h)
238     {
239 	if(!strchr(h->h_name, '.'))
240 	{
241 	    /* The official name is not fully qualified. Try looking
242 	       through the list of alternatives. */
243 	    char **aliases = h->h_aliases;
244 	    while(*aliases && !strchr(*aliases, '.'))
245 		aliases++;
246 	    system_name = rep_string_dup(*aliases ? *aliases : h->h_name);
247 	}
248 	else
249 	    system_name = rep_string_dup((char *)h->h_name);
250     }
251     else
252 	system_name = rep_string_dup(buf);
253     rep_mark_static(&system_name);
254     return system_name;
255 }
256 
257 
258 /* Main input loop */
259 
260 /* This is the set of fds we're waiting for input from. */
261 static fd_set input_fdset;
262 
263 /* For every bit set in unix_fd_read_set there should be a corresponding
264    function in here that will be called when input becomes available.
265    -- Is this really such a good idea, it's a lot of wasted space.. */
266 static void (*input_actions[FD_SETSIZE])(int);
267 
268 /* A bit set in this array means that the corresponding fd has input read
269    but not yet handled. */
270 static fd_set input_pending;
271 static int input_pending_count;
272 
273 void (*rep_register_input_fd_fun)(int fd, void (*callback)(int fd)) = 0;
274 void (*rep_deregister_input_fd_fun)(int fd) = 0;
275 
276 #define MAX_EVENT_LOOP_CALLBACKS 16
277 static int next_event_loop_callback;
278 static rep_bool (*event_loop_callbacks[MAX_EVENT_LOOP_CALLBACKS])(void);
279 
280 void
rep_register_input_fd(int fd,void (* callback)(int fd))281 rep_register_input_fd(int fd, void (*callback)(int fd))
282 {
283     FD_SET(fd, &input_fdset);
284     input_actions[fd] = callback;
285 
286     if (rep_register_input_fd_fun != 0)
287 	(*rep_register_input_fd_fun) (fd, callback);
288 
289     rep_unix_set_fd_cloexec(fd);
290 }
291 
292 void
rep_deregister_input_fd(int fd)293 rep_deregister_input_fd(int fd)
294 {
295     FD_CLR(fd, &input_fdset);
296     input_actions[fd] = NULL;
297 
298     if (rep_deregister_input_fd_fun != 0)
299 	(*rep_deregister_input_fd_fun) (fd);
300 }
301 
302 void
rep_map_inputs(void (* fun)(int fd,void (* callback)(int)))303 rep_map_inputs (void (*fun)(int fd, void (*callback)(int)))
304 {
305     int i;
306     for (i = 0; i < FD_SETSIZE; i++)
307     {
308 	if (input_actions[i] != 0)
309 	    fun (i, input_actions[i]);
310     }
311 }
312 
313 void
rep_mark_input_pending(int fd)314 rep_mark_input_pending(int fd)
315 {
316     if(!FD_ISSET(fd, &input_pending))
317     {
318 	FD_SET(fd, &input_pending);
319 	input_pending_count++;
320     }
321 }
322 
323 void
rep_unix_set_fd_nonblocking(int fd)324 rep_unix_set_fd_nonblocking(int fd)
325 {
326     int flags = fcntl(fd, F_GETFL, 0);
327     if(flags != -1)
328 	fcntl(fd, F_SETFL, flags | O_NONBLOCK);
329 }
330 
331 void
rep_unix_set_fd_blocking(int fd)332 rep_unix_set_fd_blocking(int fd)
333 {
334     int flags = fcntl(fd, F_GETFL, 0);
335     if(flags != -1)
336 	fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
337 }
338 
339 void
rep_unix_set_fd_cloexec(int fd)340 rep_unix_set_fd_cloexec(int fd)
341 {
342     /* Set close on exec flag. */
343     int tem = fcntl(fd, F_GETFD, 0);
344     if(tem != -1)
345 	fcntl(fd, F_SETFD, tem | FD_CLOEXEC);
346 }
347 
348 /* Turns on or off restarted system calls for SIG */
349 void
rep_sig_restart(int sig,rep_bool flag)350 rep_sig_restart(int sig, rep_bool flag)
351 {
352 #if defined (HAVE_SIGINTERRUPT)
353     siginterrupt (sig, !flag);
354 #else
355     struct sigaction act;
356     sigaction (sig, 0, &act);
357     if(flag)
358     {
359 # if defined (SA_RESTART)
360 	act.sa_flags |= SA_RESTART;
361 # elif defined (SA_INTERRUPT)
362 	act.sa_flags &= ~SA_INTERRUPT;
363 # endif
364     }
365     else
366     {
367 # if defined (SA_RESTART)
368 	act.sa_flags &= ~SA_RESTART;
369 # elif defined (SA_INTERRUPT)
370 	act.sa_flags |= SA_INTERRUPT;
371 # endif
372     }
373     sigaction(sig, &act, 0);
374 #endif /* !HAVE_SIGINTERRUPT */
375 }
376 
377 void
rep_add_event_loop_callback(rep_bool (* callback)(void))378 rep_add_event_loop_callback (rep_bool (*callback)(void))
379 {
380     if (next_event_loop_callback == MAX_EVENT_LOOP_CALLBACKS)
381 	abort ();
382     event_loop_callbacks [next_event_loop_callback++] = callback;
383 }
384 
385 rep_bool
rep_proc_periodically(void)386 rep_proc_periodically (void)
387 {
388     rep_bool ret = rep_FALSE;
389     int i;
390     for (i = 0; i < next_event_loop_callback; i++)
391     {
392 	if (event_loop_callbacks[i] ())
393 	    ret = rep_TRUE;
394     }
395     return ret;
396 }
397 
398 /* Wait for input for no longer than TIMEOUT-MSECS for input fds defined
399    by INPUTS. If input arrived return the number of ready fds, with the
400    actual fds defined by the fdset INPUTS. Return zero if the timeout
401    was reached. */
402 static int
wait_for_input(fd_set * inputs,unsigned long timeout_msecs)403 wait_for_input(fd_set *inputs, unsigned long timeout_msecs)
404 {
405     fd_set copy;
406     int ready = -1;
407 
408     if(input_pending_count > 0)
409     {
410 	/* Check the pending inputs first.. */
411 	fd_set out;
412 	int i, count = 0, seen = 0;
413 	for(i = 0; seen < input_pending_count && i < FD_SETSIZE; i++)
414 	{
415 	    if(FD_ISSET(i, &input_pending))
416 	    {
417 		seen++;
418 		if(FD_ISSET(i, inputs))
419 		{
420 		    if(count == 0)
421 			FD_ZERO(&out);
422 		    FD_SET(i, &out);
423 		    count++;
424 		}
425 	    }
426 	}
427 	if(count > 0)
428 	{
429 	    memcpy(inputs, &out, sizeof(out));
430 	    return count;
431 	}
432     }
433 
434     /* Allow embedders to override this part of the function. */
435 
436     if (rep_wait_for_input_fun != 0)
437 	return (*rep_wait_for_input_fun) (inputs, timeout_msecs);
438 
439     /* Break the timeout into one-second chunks, then check for
440        interrupt between each call to select. */
441     do {
442 	struct timeval timeout;
443 	unsigned long max_sleep = rep_max_sleep_for ();
444 	unsigned long this_timeout_msecs = MIN (timeout_msecs,
445 					 rep_input_timeout_secs * 1000);
446 	unsigned long actual_timeout_msecs = MIN (this_timeout_msecs, max_sleep);
447 
448 	timeout.tv_sec = actual_timeout_msecs / 1000;
449 	timeout.tv_usec = (actual_timeout_msecs % 1000) * 1000;
450 	memcpy (&copy, inputs, sizeof (copy));
451 
452 	/* Don't test for interrupts before the first call to select() */
453 	if (ready == 0)
454 	{
455 	    rep_TEST_INT_SLOW;
456 	    if (rep_INTERRUPTP)
457 		break;
458 	}
459 
460 	/* Don't want select() to restart after a SIGCHLD or SIGALRM;
461 	   there may be a notification to dispatch.  */
462 	rep_sig_restart(SIGCHLD, rep_FALSE);
463 	rep_sig_restart(SIGALRM, rep_FALSE);
464 	ready = select(FD_SETSIZE, &copy, NULL, NULL, &timeout);
465 	rep_sig_restart(SIGALRM, rep_TRUE);
466 	rep_sig_restart(SIGCHLD, rep_TRUE);
467 
468 	if (ready == 0 && actual_timeout_msecs < this_timeout_msecs)
469 	{
470 	    Fthread_suspend (Qnil, rep_MAKE_INT (this_timeout_msecs
471 						 - actual_timeout_msecs));
472 	}
473 
474 	timeout_msecs -= this_timeout_msecs;
475     } while (ready == 0 && timeout_msecs > 0);
476 
477     memcpy (inputs, &copy, sizeof (copy));
478     return ready;
479 }
480 
481 /* Handle the READY fds with pending input (defined by fdset INPUTS).
482    Return true if the display might require updating. Returns immediately
483    if a Lisp error has occurred. */
484 static rep_bool
handle_input(fd_set * inputs,int ready)485 handle_input(fd_set *inputs, int ready)
486 {
487     static long idle_period;
488     rep_bool refreshp = rep_FALSE;
489 
490     if(ready > 0)
491     {
492 	int i;
493 
494 	idle_period = 0;
495 
496 	for(i = 0; i < FD_SETSIZE && ready > 0 && !rep_INTERRUPTP; i++)
497 	{
498 	    if(FD_ISSET(i, inputs))
499 	    {
500 		ready--;
501 		if(FD_ISSET(i, &input_pending))
502 		{
503 		    FD_CLR(i, &input_pending);
504 		    input_pending_count--;
505 		}
506 		if(input_actions[i] != NULL)
507 		{
508 		    input_actions[i](i);
509 		    refreshp = rep_TRUE;
510 		}
511 	    }
512 	}
513     }
514     else if(ready == 0)
515     {
516 	/* A timeout. */
517 	if(rep_INTERRUPTP || rep_on_idle(idle_period))
518 	    refreshp = rep_TRUE;
519 
520 	idle_period++;
521     }
522 
523     if(!rep_INTERRUPTP && rep_proc_periodically())
524 	refreshp = rep_TRUE;
525 
526     return refreshp;
527 }
528 
529 /* The input handler loop. */
530 repv
rep_event_loop(void)531 rep_event_loop(void)
532 {
533     repv result = Qnil;
534 
535     if (rep_redisplay_fun != 0)
536 	(*rep_redisplay_fun)();
537 
538     while(1)
539     {
540 	int ready;
541 	rep_bool refreshp = rep_FALSE;
542 	fd_set copy;
543 
544 	if (rep_throw_value == rep_NULL)
545 	{
546 	    memcpy(&copy, &input_fdset, sizeof(copy));
547 	    ready = wait_for_input(&copy, rep_input_timeout_secs * 1000);
548 	    refreshp = handle_input(&copy, ready);
549 	}
550 
551 	/* Check for exceptional conditions. */
552 	if(rep_throw_value != rep_NULL)
553 	{
554 	    if(rep_handle_input_exception(&result))
555 		return result;
556 	    else
557 		refreshp = rep_TRUE;
558 	}
559 
560 	if(refreshp && rep_redisplay_fun != 0)
561 	    (*rep_redisplay_fun)();
562     }
563 
564     return result;
565 }
566 
567 repv
rep_sit_for(unsigned long timeout_msecs)568 rep_sit_for(unsigned long timeout_msecs)
569 {
570     fd_set copy;
571     int ready;
572     if(timeout_msecs != 0 && rep_redisplay_fun != 0)
573 	(*rep_redisplay_fun)();
574     memcpy(&copy, &input_fdset, sizeof(copy));
575     ready = wait_for_input(&copy, timeout_msecs);
576     if(rep_INTERRUPTP)
577 	return rep_NULL;
578     else
579 	return (ready > 0) ? Qnil : Qt;
580 }
581 
582 /* Wait TIMEOUT_MSECS for input, ignoring any input fds that would
583    invoke any callback function except CALLBACKS. Return Qnil if any
584    input was serviced, Qt if the timeout expired, rep_NULL for an error. */
585 repv
rep_accept_input_for_callbacks(unsigned long timeout_msecs,int ncallbacks,void (** callbacks)(int))586 rep_accept_input_for_callbacks (unsigned long timeout_msecs, int ncallbacks,
587 				void (**callbacks)(int))
588 {
589     fd_set copy;
590     int ready, i;
591     FD_ZERO(&copy);
592     for(i = 0; i < FD_SETSIZE; i++)
593     {
594 	if(FD_ISSET(i, &input_fdset))
595 	{
596 	    int j;
597 	    for (j = 0; j < ncallbacks; j++)
598 	    {
599 		if (input_actions[i] == callbacks[j])
600 		{
601 		    FD_SET(i, &copy);
602 		    break;
603 		}
604 	    }
605 	}
606     }
607     ready = wait_for_input(&copy, timeout_msecs);
608     if(ready > 0 && !rep_INTERRUPTP)
609 	handle_input(&copy, ready);
610     if(rep_INTERRUPTP)
611 	return rep_NULL;
612     else
613 	return ready > 0 ? Qnil : Qt;
614 }
615 
616 /* Wait TIMEOUT_MSECS for input from the NFDS file descriptors stored in FDS.
617    Return Qnil if any input was serviced, Qt if the timeout expired, rep_NULL
618    for an error. */
619 repv
rep_accept_input_for_fds(unsigned long timeout_msecs,int nfds,int * fds)620 rep_accept_input_for_fds (unsigned long timeout_msecs, int nfds, int *fds)
621 {
622     fd_set copy;
623     int ready, i;
624     FD_ZERO(&copy);
625     for(i = 0; i < nfds; i++)
626     {
627 	if(FD_ISSET(fds[i], &input_fdset))
628 	    FD_SET(fds[i], &copy);
629     }
630     ready = wait_for_input(&copy, timeout_msecs);
631     if(ready > 0 && !rep_INTERRUPTP)
632 	handle_input(&copy, ready);
633     if(rep_INTERRUPTP)
634 	return rep_NULL;
635     else
636 	return ready > 0 ? Qnil : Qt;
637 }
638 
639 /* obsolete, for compatibility only */
640 repv
rep_accept_input(unsigned long timeout_msecs,void (* callback)(int))641 rep_accept_input(unsigned long timeout_msecs, void (*callback)(int))
642 {
643     return rep_accept_input_for_callbacks (timeout_msecs, 1, &callback);
644 }
645 
646 rep_bool
rep_poll_input(int fd)647 rep_poll_input(int fd)
648 {
649     fd_set in;
650     FD_ZERO(&in);
651     FD_SET(fd, &in);
652     return wait_for_input(&in, 0);
653 }
654 
655 
656 /* Memory allocation; most of these are normally macros in unix_defs.h */
657 
658 #ifdef DEBUG_SYS_ALLOC
659 struct alloc_data {
660     struct alloc_data *next;
661     size_t size;
662     void *function;
663     double unused;			/* double to force good alignment */
664 };
665 
666 #define SIZEOF_ALLOC_DATA (sizeof (struct alloc_data) - sizeof (double))
667 
668 static struct alloc_data *allocations;
669 
670 void *
rep_alloc(unsigned int length)671 rep_alloc(unsigned int length)
672 {
673     void *mem;
674     length += SIZEOF_ALLOC_DATA;
675     mem = malloc(length);
676     if(mem != 0)
677     {
678 	struct alloc_data *x = mem;
679 
680 	/* Check that the alignment promised actually occurs */
681 	assert((((rep_PTR_SIZED_INT)mem) & (rep_MALLOC_ALIGNMENT - 1)) == 0);
682 
683 	mem = ((char *)mem) + SIZEOF_ALLOC_DATA;
684 	x->next = allocations;
685 	allocations = x;
686 	x->size = length - SIZEOF_ALLOC_DATA;
687 	x->function = rep_db_return_address();
688     }
689     return mem;
690 }
691 
692 void *
rep_realloc(void * ptr,unsigned int length)693 rep_realloc(void *ptr, unsigned int length)
694 {
695     void *mem;
696     length += SIZEOF_ALLOC_DATA;
697     ptr = (void *)(((char *)ptr) - SIZEOF_ALLOC_DATA);
698     mem = realloc(ptr, length);
699     if(mem != 0)
700     {
701 	struct alloc_data *x = mem;
702 
703 	/* Check that the alignment promised actually occurs */
704 	assert((((rep_PTR_SIZED_INT)mem) & (rep_MALLOC_ALIGNMENT - 1)) == 0);
705 
706 	if(allocations == ptr)
707 	    allocations = x;
708 	else
709 	{
710 	    struct alloc_data *p = allocations;
711 	    while(p->next != ptr)
712 		p = p->next;
713 	    p->next = x;
714 	}
715 	mem = ((char *)mem) + SIZEOF_ALLOC_DATA;
716 	x->size = length - SIZEOF_ALLOC_DATA;
717 	x->function = rep_db_return_address();
718     }
719     return mem;
720 }
721 
722 void
rep_free(void * ptr)723 rep_free(void *ptr)
724 {
725     struct alloc_data *x = (struct alloc_data *)(((char *)ptr) - SIZEOF_ALLOC_DATA);
726     struct alloc_data **p = &allocations;
727     while(*p != 0 && (*p) != x)
728 	p = &((*p)->next);
729     assert(*p != 0);
730     (*p) = x->next;
731     free(x);
732 }
733 
734 void
rep_print_allocations(void)735 rep_print_allocations(void)
736 {
737     if(allocations != 0)
738     {
739 	struct alloc_data *x = allocations;
740 	fprintf(stderr, "\n\nOutstanding allocations:\n\n");
741 	while(x != 0)
742 	{
743 	    char *sname;
744 	    void *saddr;
745 	    fprintf(stderr, "\t(%p, %d)",
746 		    ((char *)x) + SIZEOF_ALLOC_DATA, x->size);
747 	    if(rep_find_c_symbol(x->function, &sname, &saddr))
748 		fprintf(stderr, "\t\t<%s+%d>", sname, x->function - saddr);
749 	    fprintf(stderr, "\n");
750 	    x = x->next;
751 	}
752     }
753 }
754 
755 DEFUN("unix-print-allocations", Funix_print_allocations,
756       Sunix_print_allocations, (void), rep_Subr0) /*
757 ::doc:rep.lang.debug#unix-print-allocations::
758 unix-print-allocations
759 
760 Output a list of all allocated memory blocks to standard error.
761 ::end:: */
762 {
763     rep_print_allocations();
764     return Qt;
765 }
766 #endif
767 
768 
769 /* Standard signal handlers */
770 
771 static volatile rep_bool in_fatal_signal_handler;
772 
773 /* Invoked by any of the handlable error reporting signals */
774 static RETSIGTYPE
fatal_signal_handler(int sig)775 fatal_signal_handler(int sig)
776 {
777     /* Sometimes this function can get in an infinite loop, even with the
778        in_fatal_signal_handler exclusion? Does this help..? */
779     signal(sig, SIG_DFL);
780 
781     /* Check for nested calls to this function */
782     if(in_fatal_signal_handler)
783 	raise(sig);
784     in_fatal_signal_handler = rep_TRUE;
785 
786 #ifdef HAVE_PSIGNAL
787     psignal(sig, "rep: received fatal signal");
788 #else
789 # ifdef HAVE_STRSIGNAL
790     fprintf(stderr, "rep: received fatal signal: %s\n", strsignal(sig));
791 # else
792     fprintf(stderr, "rep: received fatal signal: %d\n", sig);
793 # endif
794 #endif
795 
796     /* Save the C backtrace */
797     rep_db_print_backtrace(rep_common_db, "fatal_signal_handler");
798 
799     /* Output all debug buffers */
800     rep_db_spew_all();
801 
802     /* Try and output the Lisp call stack; this may or may not
803        provoke another error, but who cares.. */
804     fprintf(stderr, "\nLisp backtrace:\n");
805     Fbacktrace(Fstderr_file());
806     fputs("\n", stderr);
807 
808     /* Now reraise the signal, since it's currently blocked
809        the default action will occur, i.e. termination */
810     raise(sig);
811 }
812 
813 /* Invoked by SIGINT (i.e. ^C) */
814 static RETSIGTYPE
interrupt_signal_handler(int sig)815 interrupt_signal_handler(int sig)
816 {
817     if (rep_throw_value == rep_int_cell)
818     {
819 	signal (sig, SIG_DFL);
820 	raise (sig);
821     }
822     else
823     {
824 	rep_throw_value = rep_int_cell;
825 	signal (sig, interrupt_signal_handler);
826     }
827 }
828 
829 /* Invoked by trappable termination signals */
830 static RETSIGTYPE
termination_signal_handler(int sig)831 termination_signal_handler(int sig)
832 {
833     if (rep_throw_value == rep_term_cell)
834     {
835 	signal (sig, SIG_DFL);
836 	raise (sig);
837     }
838     else
839     {
840 	rep_throw_value = rep_term_cell;
841 	signal (sig, termination_signal_handler);
842     }
843 }
844 
845 /* Invoked by SIGUSR1 or SIGUSR2 */
846 static RETSIGTYPE
usr_signal_handler(int sig)847 usr_signal_handler (int sig)
848 {
849     switch (sig)
850     {
851     case SIGUSR1:
852 	fprintf(stderr, "\n\nLisp backtrace:\n");
853 	Fbacktrace(Fstderr_file());
854 	fputs("\n\n", stderr);
855 	break;
856 
857     case SIGUSR2:
858 	fprintf (stderr, "\n\nDebug buffers:\n");
859 	rep_db_spew_all ();
860 	fputc ('\n', stderr);
861 	break;
862     }
863     signal (sig, usr_signal_handler);
864 }
865 
866 
867 /* Initialisation */
868 
869 /* This function is called _before_ almost anything else; but
870    most importantly, it's called before sys_init() (i.e. we
871    start opening displays) */
872 void
rep_pre_sys_os_init(void)873 rep_pre_sys_os_init(void)
874 {
875     FD_ZERO(&input_fdset);
876     FD_ZERO(&input_pending);
877 
878     /* First the error signals */
879 #ifndef IGNORE_FATAL_SIGNALS
880 #ifdef SIGFPE
881     if(signal(SIGFPE, fatal_signal_handler) == SIG_IGN)
882 	signal(SIGFPE, SIG_IGN);
883 #endif
884 #ifdef SIGILL
885     if(signal(SIGILL, fatal_signal_handler) == SIG_IGN)
886 	signal(SIGILL, SIG_IGN);
887 #endif
888 #ifdef SIGSEGV
889     if(signal(SIGSEGV, fatal_signal_handler) == SIG_IGN)
890 	signal(SIGSEGV, SIG_IGN);
891 #endif
892 #ifdef SIGBUS
893     if(signal(SIGBUS, fatal_signal_handler) == SIG_IGN)
894 	signal(SIGBUS, SIG_IGN);
895 #endif
896 #ifdef SIGQUIT
897     if(signal(SIGQUIT, fatal_signal_handler) == SIG_IGN)
898 	signal(SIGQUIT, SIG_IGN);
899 #endif
900 #ifdef SIGABRT
901     if(signal(SIGABRT, fatal_signal_handler) == SIG_IGN)
902 	signal(SIGABRT, SIG_IGN);
903 #endif
904 #endif
905 
906     /* Install the interrupt handler */
907 #ifdef SIGINT
908     if(signal(SIGINT, interrupt_signal_handler) == SIG_IGN)
909 	signal(SIGINT, SIG_IGN);
910     else
911 	rep_sig_restart (SIGINT, rep_FALSE);
912 #endif
913 
914     /* Finally, the termination signals */
915 #ifdef SIGTERM
916     if(signal(SIGTERM, termination_signal_handler) == SIG_IGN)
917 	signal(SIGTERM, SIG_IGN);
918     else
919 	rep_sig_restart (SIGTERM, rep_FALSE);
920 #endif
921 #ifdef SIGHUP
922     if(signal(SIGHUP, termination_signal_handler) == SIG_IGN)
923 	signal(SIGHUP, SIG_IGN);
924     else
925 	rep_sig_restart (SIGHUP, rep_FALSE);
926 #endif
927 
928 #ifdef SIGUSR1
929     signal(SIGUSR1, usr_signal_handler);
930 #endif
931 #ifdef SIGUSR2
932     signal(SIGUSR2, usr_signal_handler);
933 #endif
934 }
935 
936 /* More normal initialisation. */
937 void
rep_sys_os_init(void)938 rep_sys_os_init(void)
939 {
940     repv env;
941     char **ptr;
942 
943     /* Initialise process-environment variable */
944     env = Qnil;
945     if (environ != 0)
946     {
947 	ptr = environ;
948 	while(*ptr != 0)
949 	    env = Fcons(rep_string_dup(*ptr++), env);
950     }
951     Fset (Qprocess_environment, env);
952 
953 #ifdef DEBUG_SYS_ALLOC
954     { repv tem = rep_push_structure ("rep.lang.debug");
955       rep_ADD_SUBR(Sunix_print_allocations);
956       rep_pop_structure (tem); }
957 #endif
958 
959     rep_proc_init();
960 }
961 
962 void
rep_sys_os_kill(void)963 rep_sys_os_kill(void)
964 {
965     rep_proc_kill();
966 }
967