Don't crash if internal-char-font is called on non-GUI frames.
[bpt/emacs.git] / src / sysdep.c
CommitLineData
86a5659e 1/* Interfaces to system-dependent kernel and library entries.
acaf905b 2 Copyright (C) 1985-1988, 1993-1995, 1999-2012
8cabe764 3 Free Software Foundation, Inc.
86a5659e
JB
4
5This file is part of GNU Emacs.
6
9ec0b715 7GNU Emacs is free software: you can redistribute it and/or modify
86a5659e 8it under the terms of the GNU General Public License as published by
9ec0b715
GM
9the Free Software Foundation, either version 3 of the License, or
10(at your option) any later version.
86a5659e
JB
11
12GNU Emacs is distributed in the hope that it will be useful,
13but WITHOUT ANY WARRANTY; without even the implied warranty of
14MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15GNU General Public License for more details.
16
17You should have received a copy of the GNU General Public License
9ec0b715 18along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
86a5659e 19
4838e624 20#include <config.h>
f162bcc3
PE
21
22#define SYSTIME_INLINE EXTERN_INLINE
23
cf29dd84 24#include <execinfo.h>
5890e9f7 25#include <stdio.h>
06e111a6
DN
26#ifdef HAVE_PWD_H
27#include <pwd.h>
28#include <grp.h>
29#endif /* HAVE_PWD_H */
06e111a6 30#include <limits.h>
d3eb3bfa 31#include <unistd.h>
53934c98 32
d1fdcab7 33#include <allocator.h>
620f13b0 34#include <c-ctype.h>
d1fdcab7 35#include <careadlinkat.h>
67342916 36#include <ignore-value.h>
d35af63c 37#include <utimens.h>
67342916 38
86a5659e 39#include "lisp.h"
819b8f00 40#include "sysselect.h"
9ac0d9e0 41#include "blockinput.h"
86a5659e 42
7dca65a4
PE
43#ifdef BSD_SYSTEM
44#include <sys/param.h>
b91b7e4d 45#include <sys/sysctl.h>
7dca65a4
PE
46#endif
47
48#ifdef __FreeBSD__
b91b7e4d 49#include <sys/user.h>
d054f3fb 50#include <sys/resource.h>
b91b7e4d
EW
51#include <math.h>
52#endif
53
fe03522b 54#ifdef WINDOWSNT
e15b6288
JR
55#define read sys_read
56#define write sys_write
62aba0d4
FP
57#ifndef STDERR_FILENO
58#define STDERR_FILENO fileno(GetStdHandle(STD_ERROR_HANDLE))
59#endif
fe03522b 60#include <windows.h>
fe03522b
RS
61#endif /* not WINDOWSNT */
62
86a5659e
JB
63#include <sys/types.h>
64#include <sys/stat.h>
65#include <errno.h>
66
b05af5d3
PE
67/* Get SI_SRPC_DOMAIN, if it is available. */
68#ifdef HAVE_SYS_SYSTEMINFO_H
69#include <sys/systeminfo.h>
70#endif
71
207bdbdb 72#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
207bdbdb
RS
73#include "msdos.h"
74#include <sys/param.h>
15614e61 75#endif
207bdbdb 76
bb4bc8e2 77#include <sys/file.h>
bb4bc8e2 78#include <fcntl.h>
86a5659e 79
e04a4e0d 80#include "systty.h"
94c8642a 81#include "syswait.h"
86a5659e 82
a7ebc409 83#ifdef HAVE_SYS_UTSNAME_H
86a5659e 84#include <sys/utsname.h>
86a5659e 85#include <memory.h>
a7ebc409 86#endif /* HAVE_SYS_UTSNAME_H */
86a5659e 87
e36ec798 88#include "keyboard.h"
0137dbf7 89#include "frame.h"
86a5659e
JB
90#include "window.h"
91#include "termhooks.h"
92#include "termchar.h"
93#include "termopts.h"
94#include "dispextern.h"
95#include "process.h"
0a125897 96#include "cm.h" /* for reset_sys_modes */
86a5659e 97
fe03522b
RS
98#ifdef WINDOWSNT
99#include <direct.h>
100/* In process.h which conflicts with the local copy. */
101#define _P_WAIT 0
43db14bb
JB
102int _cdecl _spawnlp (int, const char *, const char *, ...);
103int _cdecl _getpid (void);
b6682dd9 104extern char *getwd (char *);
fe03522b
RS
105#endif
106
91bac16a
JB
107#include "syssignal.h"
108#include "systime.h"
86a5659e 109
1fa53021
PE
110static int emacs_get_tty (int, struct emacs_tty *);
111static int emacs_set_tty (int, struct emacs_tty *, int);
112
5a16b9bc
PE
113/* ULLONG_MAX is missing on Red Hat Linux 7.3; see Bug#11781. */
114#ifndef ULLONG_MAX
115#define ULLONG_MAX TYPE_MAXIMUM (unsigned long long int)
116#endif
117
ff2e8052
DN
118/* Declare here, including term.h is problematic on some systems. */
119extern void tputs (const char *, int, int (*)(int));
120
91433552 121static const int baud_convert[] =
86a5659e
JB
122 {
123 0, 50, 75, 110, 135, 150, 200, 300, 600, 1200,
124 1800, 2400, 4800, 9600, 19200, 38400
125 };
86a5659e 126
f78f1a83 127
3480d92b 128#if !defined (HAVE_GET_CURRENT_DIR_NAME) || defined (BROKEN_GET_CURRENT_DIR_NAME)
f78f1a83 129
b6682dd9 130/* Return the current working directory. Returns NULL on errors.
f78f1a83
EZ
131 Any other returned value must be freed with free. This is used
132 only when get_current_dir_name is not defined on the system. */
133char*
cf84bb53 134get_current_dir_name (void)
f78f1a83
EZ
135{
136 char *buf;
137 char *pwd;
138 struct stat dotstat, pwdstat;
139 /* If PWD is accurate, use it instead of calling getwd. PWD is
140 sometimes a nicer name, and using it may avoid a fatal error if a
141 parent directory is searchable but not readable. */
142 if ((pwd = getenv ("PWD")) != 0
143 && (IS_DIRECTORY_SEP (*pwd) || (*pwd && IS_DEVICE_SEP (pwd[1])))
144 && stat (pwd, &pwdstat) == 0
145 && stat (".", &dotstat) == 0
146 && dotstat.st_ino == pwdstat.st_ino
147 && dotstat.st_dev == pwdstat.st_dev
148#ifdef MAXPATHLEN
149 && strlen (pwd) < MAXPATHLEN
150#endif
151 )
152 {
38182d90 153 buf = malloc (strlen (pwd) + 1);
f78f1a83
EZ
154 if (!buf)
155 return NULL;
156 strcpy (buf, pwd);
157 }
158#ifdef HAVE_GETCWD
159 else
160 {
161 size_t buf_size = 1024;
38182d90 162 buf = malloc (buf_size);
f78f1a83
EZ
163 if (!buf)
164 return NULL;
165 for (;;)
166 {
167 if (getcwd (buf, buf_size) == buf)
168 break;
169 if (errno != ERANGE)
170 {
171 int tmp_errno = errno;
172 free (buf);
173 errno = tmp_errno;
174 return NULL;
175 }
176 buf_size *= 2;
38182d90 177 buf = realloc (buf, buf_size);
f78f1a83
EZ
178 if (!buf)
179 return NULL;
180 }
181 }
182#else
183 else
184 {
185 /* We need MAXPATHLEN here. */
38182d90 186 buf = malloc (MAXPATHLEN + 1);
f78f1a83
EZ
187 if (!buf)
188 return NULL;
189 if (getwd (buf) == NULL)
190 {
191 int tmp_errno = errno;
192 free (buf);
193 errno = tmp_errno;
194 return NULL;
195 }
196 }
197#endif
198 return buf;
199}
200#endif
201
64e971c3 202\f
9628b887 203/* Discard pending input on all input descriptors. */
91bac16a 204
08633194 205void
971de7fb 206discard_tty_input (void)
86a5659e 207{
fe03522b 208#ifndef WINDOWSNT
91bac16a 209 struct emacs_tty buf;
86a5659e
JB
210
211 if (noninteractive)
212 return;
213
fe03522b 214#ifdef MSDOS /* Demacs 1.1.1 91/10/16 HIRANO Satoshi */
207bdbdb 215 while (dos_keyread () != -1)
fe03522b 216 ;
207bdbdb 217#else /* not MSDOS */
9628b887 218 {
28d7d09f 219 struct tty_display_info *tty;
9628b887
KL
220 for (tty = tty_list; tty; tty = tty->next)
221 {
0b0d3e0b
KL
222 if (tty->input) /* Is the device suspended? */
223 {
12e610e8
DN
224 emacs_get_tty (fileno (tty->input), &buf);
225 emacs_set_tty (fileno (tty->input), &buf, 0);
0b0d3e0b 226 }
9628b887
KL
227 }
228 }
207bdbdb 229#endif /* not MSDOS */
fe03522b 230#endif /* not WINDOWSNT */
86a5659e
JB
231}
232
16c290d8 233\f
86a5659e
JB
234#ifdef SIGTSTP
235
64e971c3 236/* Arrange for character C to be read as the next input from
16c290d8
KL
237 the terminal.
238 XXX What if we have multiple ttys?
239*/
64e971c3 240
dfcf069d 241void
0c2338d8 242stuff_char (char c)
86a5659e 243{
428a555e 244 if (! FRAME_TERMCAP_P (SELECTED_FRAME ()))
23dab951
RS
245 return;
246
86a5659e
JB
247/* Should perhaps error if in batch mode */
248#ifdef TIOCSTI
0b0d3e0b 249 ioctl (fileno (CURTTY()->input), TIOCSTI, &c);
86a5659e 250#else /* no TIOCSTI */
71f06467 251 error ("Cannot stuff terminal input characters in this version of Unix");
86a5659e
JB
252#endif /* no TIOCSTI */
253}
254
255#endif /* SIGTSTP */
64e971c3 256\f
08633194 257void
16c290d8 258init_baud_rate (int fd)
86a5659e 259{
4c620157 260 int emacs_ospeed;
67342916 261
86a5659e 262 if (noninteractive)
5bdd7bdd 263 emacs_ospeed = 0;
86a5659e
JB
264 else
265 {
fe03522b 266#ifdef DOS_NT
5bdd7bdd 267 emacs_ospeed = 15;
fe03522b 268#else /* not DOS_NT */
e04a4e0d 269 struct termios sg;
91bac16a 270
71f06467 271 sg.c_cflag = B9600;
16c290d8 272 tcgetattr (fd, &sg);
5bdd7bdd 273 emacs_ospeed = cfgetospeed (&sg);
fe03522b 274#endif /* not DOS_NT */
86a5659e 275 }
177c0ea7 276
5bdd7bdd
GM
277 baud_rate = (emacs_ospeed < sizeof baud_convert / sizeof baud_convert[0]
278 ? baud_convert[emacs_ospeed] : 9600);
86a5659e
JB
279 if (baud_rate == 0)
280 baud_rate = 1200;
281}
282
16c290d8 283\f
86a5659e 284
77defa9a 285#ifndef MSDOS
86a5659e 286
e7a6747f 287static void
d311d28c 288wait_for_termination_1 (pid_t pid, int interruptible)
86a5659e
JB
289{
290 while (1)
291 {
d4547511
PE
292#ifdef WINDOWSNT
293 wait (0);
294 break;
295#else /* not WINDOWSNT */
4d7e6e51
PE
296 int status;
297 int wait_result = waitpid (pid, &status, 0);
298 if (wait_result < 0)
9ab714c7 299 {
4d7e6e51
PE
300 if (errno != EINTR)
301 break;
302 }
303 else
304 {
305 record_child_status_change (wait_result, status);
9ab714c7
RS
306 break;
307 }
ac3ac859 308
d4547511 309#endif /* not WINDOWSNT */
1ef14cb4
LMI
310 if (interruptible)
311 QUIT;
86a5659e
JB
312 }
313}
314
e7a6747f
AS
315/* Wait for subprocess with process id `pid' to terminate and
316 make sure it will get eliminated (not remain forever as a zombie) */
317
318void
d311d28c 319wait_for_termination (pid_t pid)
e7a6747f
AS
320{
321 wait_for_termination_1 (pid, 0);
322}
323
324/* Like the above, but allow keyboard interruption. */
325void
d311d28c 326interruptible_wait_for_termination (pid_t pid)
e7a6747f
AS
327{
328 wait_for_termination_1 (pid, 1);
329}
330
86a5659e
JB
331/*
332 * flush any pending output
333 * (may flush input as well; it does not matter the way we use it)
334 */
177c0ea7 335
08633194 336void
971de7fb 337flush_pending_output (int channel)
86a5659e 338{
9de940b5 339 /* FIXME: maybe this function should be removed */
86a5659e 340}
64e971c3 341\f
86a5659e
JB
342/* Set up the terminal at the other end of a pseudo-terminal that
343 we will be controlling an inferior through.
344 It should not echo or do line-editing, since that is done
345 in Emacs. No padding needed for insertion into an Emacs buffer. */
346
08633194 347void
971de7fb 348child_setup_tty (int out)
86a5659e 349{
77defa9a 350#ifndef WINDOWSNT
91bac16a
JB
351 struct emacs_tty s;
352
12e610e8 353 emacs_get_tty (out, &s);
91bac16a
JB
354 s.main.c_oflag |= OPOST; /* Enable output postprocessing */
355 s.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL on output */
9d4e5eea 356#ifdef NLDLY
07cfc4e7
GM
357 /* http://lists.gnu.org/archive/html/emacs-devel/2008-05/msg00406.html
358 Some versions of GNU Hurd do not have FFDLY? */
359#ifdef FFDLY
91bac16a
JB
360 s.main.c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY|FFDLY);
361 /* No output delays */
07cfc4e7
GM
362#else
363 s.main.c_oflag &= ~(NLDLY|CRDLY|TABDLY|BSDLY|VTDLY);
364 /* No output delays */
365#endif
9d4e5eea 366#endif
91bac16a
JB
367 s.main.c_lflag &= ~ECHO; /* Disable echo */
368 s.main.c_lflag |= ISIG; /* Enable signals */
9d4e5eea
RS
369#ifdef IUCLC
370 s.main.c_iflag &= ~IUCLC; /* Disable downcasing on input. */
371#endif
f7097b2a
RS
372#ifdef ISTRIP
373 s.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
374#endif
23e4c8be 375#ifdef OLCUC
9d4e5eea
RS
376 s.main.c_oflag &= ~OLCUC; /* Disable upcasing on output. */
377#endif
f7097b2a 378 s.main.c_oflag &= ~TAB3; /* Disable tab expansion */
1bf96fb5 379 s.main.c_cflag = (s.main.c_cflag & ~CSIZE) | CS8; /* Don't strip 8th bit */
441f6399
RS
380 s.main.c_cc[VERASE] = CDISABLE; /* disable erase processing */
381 s.main.c_cc[VKILL] = CDISABLE; /* disable kill processing */
91bac16a 382
86a5659e 383#ifdef HPUX
91bac16a 384 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
86a5659e 385#endif /* HPUX */
91bac16a 386
dfe598b5
RS
387#ifdef SIGNALS_VIA_CHARACTERS
388 /* the QUIT and INTR character are used in process_send_signal
389 so set them here to something useful. */
fa51fa32 390 if (s.main.c_cc[VQUIT] == CDISABLE)
dfe598b5 391 s.main.c_cc[VQUIT] = '\\'&037; /* Control-\ */
fa51fa32 392 if (s.main.c_cc[VINTR] == CDISABLE)
dfe598b5
RS
393 s.main.c_cc[VINTR] = 'C'&037; /* Control-C */
394#endif /* not SIGNALS_VIA_CHARACTERS */
395
86a5659e 396#ifdef AIX
86a5659e
JB
397 /* Also, PTY overloads NUL and BREAK.
398 don't ignore break, but don't signal either, so it looks like NUL. */
91bac16a
JB
399 s.main.c_iflag &= ~IGNBRK;
400 s.main.c_iflag &= ~BRKINT;
dfe598b5
RS
401 /* rms: Formerly it set s.main.c_cc[VINTR] to 0377 here
402 unconditionally. Then a SIGNALS_VIA_CHARACTERS conditional
403 would force it to 0377. That looks like duplicated code. */
91bac16a 404 s.main.c_cflag = (s.main.c_cflag & ~CBAUD) | B9600; /* baud rate sanity */
86a5659e
JB
405#endif /* AIX */
406
aaa0a19a 407 /* We originally enabled ICANON (and set VEOF to 04), and then had
c80e3b4a 408 process.c send additional EOF chars to flush the output when faced
aaa0a19a 409 with long lines, but this leads to weird effects when the
2b0a91e7
SM
410 subprocess has disabled ICANON and ends up seeing those spurious
411 extra EOFs. So we don't send EOFs any more in
aaa0a19a
SM
412 process.c:send_process. First we tried to disable ICANON by
413 default, so if a subsprocess sets up ICANON, it's his problem (or
414 the Elisp package that talks to it) to deal with lines that are
415 too long. But this disables some features, such as the ability
416 to send EOF signals. So we re-enabled ICANON but there is no
417 more "send eof to flush" going on (which is wrong and unportable
418 in itself). The correct way to handle too much output is to
419 buffer what could not be written and then write it again when
420 select returns ok for writing. This has it own set of
421 problems. Write is now asynchronous, is that a problem? How much
422 do we buffer, and what do we do when that limit is reached? */
9a747ba6
JD
423
424 s.main.c_lflag |= ICANON; /* Enable line editing and eof processing */
425 s.main.c_cc[VEOF] = 'D'&037; /* Control-D */
3d15fe78 426#if 0 /* These settings only apply to non-ICANON mode. */
2b0a91e7
SM
427 s.main.c_cc[VMIN] = 1;
428 s.main.c_cc[VTIME] = 0;
aaa0a19a 429#endif
2b0a91e7 430
12e610e8 431 emacs_set_tty (out, &s, 0);
77defa9a 432#endif /* not WINDOWSNT */
86a5659e 433}
57507bf8 434#endif /* not MSDOS */
86a5659e 435
64e971c3 436\f
2fe28299 437/* Record a signal code and the action for it. */
86a5659e
JB
438struct save_signal
439{
440 int code;
2fe28299 441 struct sigaction action;
86a5659e
JB
442};
443
f57e2426
J
444static void save_signal_handlers (struct save_signal *);
445static void restore_signal_handlers (struct save_signal *);
35a05cca 446
86a5659e
JB
447/* Suspend the Emacs process; give terminal to its superior. */
448
08633194 449void
971de7fb 450sys_suspend (void)
86a5659e 451{
c4ea52a6 452#if defined (SIGTSTP) && !defined (MSDOS)
86a5659e 453
5a570e37 454 {
69deda53 455 pid_t pgrp = EMACS_GETPGRP (0);
5a570e37
JB
456 EMACS_KILLPG (pgrp, SIGTSTP);
457 }
86a5659e
JB
458
459#else /* No SIGTSTP */
86a5659e
JB
460/* On a system where suspending is not implemented,
461 instead fork a subshell and let it talk directly to the terminal
462 while we wait. */
a0932daa
KH
463 sys_subshell ();
464
a0932daa 465#endif /* no SIGTSTP */
a0932daa
KH
466}
467
468/* Fork a subshell. */
469
08633194 470void
971de7fb 471sys_subshell (void)
a0932daa 472{
ad00c243 473#ifdef DOS_NT /* Demacs 1.1.2 91/10/20 Manabu Higashida */
a0932daa
KH
474 int st;
475 char oldwd[MAXPATHLEN+1]; /* Fixed length is safe on MSDOS. */
476#endif
efa04277 477 int pid;
86a5659e 478 struct save_signal saved_handlers[5];
efa04277 479 Lisp_Object dir;
5e41f65d 480 unsigned char *volatile str_volatile = 0;
7e9123a2 481 unsigned char *str;
efa04277 482 int len;
86a5659e
JB
483
484 saved_handlers[0].code = SIGINT;
485 saved_handlers[1].code = SIGQUIT;
486 saved_handlers[2].code = SIGTERM;
4a4bbad2 487#ifdef USABLE_SIGIO
86a5659e
JB
488 saved_handlers[3].code = SIGIO;
489 saved_handlers[4].code = 0;
490#else
491 saved_handlers[3].code = 0;
492#endif
493
efa04277
RS
494 /* Mentioning current_buffer->buffer would mean including buffer.h,
495 which somehow wedges the hp compiler. So instead... */
496
497 dir = intern ("default-directory");
0e7e7a58 498 if (NILP (Fboundp (dir)))
efa04277
RS
499 goto xyzzy;
500 dir = Fsymbol_value (dir);
914e81a2 501 if (!STRINGP (dir))
efa04277
RS
502 goto xyzzy;
503
504 dir = expand_and_dir_to_file (Funhandled_file_name_directory (dir), Qnil);
38182d90 505 str_volatile = str = alloca (SCHARS (dir) + 2);
d5db4077 506 len = SCHARS (dir);
72af86bd 507 memcpy (str, SDATA (dir), len);
efa04277
RS
508 if (str[len - 1] != '/') str[len++] = '/';
509 str[len] = 0;
510 xyzzy:
511
ad00c243 512#ifdef DOS_NT
7964ba9e 513 pid = 0;
718ca3cf
RS
514 save_signal_handlers (saved_handlers);
515 synch_process_alive = 1;
177c0ea7 516#else
efa04277 517 pid = vfork ();
86a5659e
JB
518 if (pid == -1)
519 error ("Can't spawn subshell");
7964ba9e
RS
520#endif
521
86a5659e
JB
522 if (pid == 0)
523 {
8ea90aa3 524 const char *sh = 0;
86a5659e 525
ad00c243 526#ifdef DOS_NT /* MW, Aug 1993 */
207bdbdb 527 getwd (oldwd);
7964ba9e
RS
528 if (sh == 0)
529 sh = (char *) egetenv ("SUSPEND"); /* KFS, 1994-12-14 */
207bdbdb 530#endif
7964ba9e
RS
531 if (sh == 0)
532 sh = (char *) egetenv ("SHELL");
86a5659e
JB
533 if (sh == 0)
534 sh = "sh";
207bdbdb 535
86a5659e 536 /* Use our buffer's default directory for the subshell. */
5e41f65d 537 str = str_volatile;
32299e33
PE
538 if (str && chdir ((char *) str) != 0)
539 {
540#ifndef DOS_NT
541 ignore_value (write (1, "Can't chdir\n", 12));
542 _exit (1);
543#endif
544 }
efa04277 545
86a5659e 546 close_process_descs (); /* Close Emacs's pipes/ptys */
1593c2fe 547
fe03522b 548#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
c0917202 549 {
48178f9a
EZ
550 char *epwd = getenv ("PWD");
551 char old_pwd[MAXPATHLEN+1+4];
c0917202
EZ
552
553 /* If PWD is set, pass it with corrected value. */
48178f9a 554 if (epwd)
c0917202 555 {
48178f9a 556 strcpy (old_pwd, epwd);
c0917202
EZ
557 if (str[len - 1] == '/')
558 str[len - 1] = '\0';
559 setenv ("PWD", str, 1);
560 }
561 st = system (sh);
32299e33 562 chdir (oldwd); /* FIXME: Do the right thing on chdir failure. */
48178f9a 563 if (epwd)
c0917202
EZ
564 putenv (old_pwd); /* restore previous value */
565 }
207bdbdb 566#else /* not MSDOS */
fe03522b 567#ifdef WINDOWSNT
fe03522b
RS
568 /* Waits for process completion */
569 pid = _spawnlp (_P_WAIT, sh, sh, NULL);
32299e33 570 chdir (oldwd); /* FIXME: Do the right thing on chdir failure. */
fe03522b
RS
571 if (pid == -1)
572 write (1, "Can't execute subshell", 22);
fe03522b 573#else /* not WINDOWSNT */
e120ea40 574 execlp (sh, sh, (char *) 0);
67342916 575 ignore_value (write (1, "Can't execute subshell", 22));
86a5659e 576 _exit (1);
fe03522b 577#endif /* not WINDOWSNT */
207bdbdb 578#endif /* not MSDOS */
86a5659e
JB
579 }
580
718ca3cf 581 /* Do this now if we did not do it before. */
ed68db4d 582#ifndef MSDOS
86a5659e 583 save_signal_handlers (saved_handlers);
ffafc793 584 synch_process_alive = 1;
718ca3cf
RS
585#endif
586
ad00c243 587#ifndef DOS_NT
86a5659e 588 wait_for_termination (pid);
7964ba9e 589#endif
86a5659e 590 restore_signal_handlers (saved_handlers);
718ca3cf 591 synch_process_alive = 0;
86a5659e
JB
592}
593
35a05cca 594static void
971de7fb 595save_signal_handlers (struct save_signal *saved_handlers)
86a5659e
JB
596{
597 while (saved_handlers->code)
598 {
2fe28299
PE
599 struct sigaction action;
600 emacs_sigaction_init (&action, SIG_IGN);
601 sigaction (saved_handlers->code, &action, &saved_handlers->action);
86a5659e
JB
602 saved_handlers++;
603 }
604}
605
35a05cca 606static void
971de7fb 607restore_signal_handlers (struct save_signal *saved_handlers)
86a5659e
JB
608{
609 while (saved_handlers->code)
610 {
2fe28299 611 sigaction (saved_handlers->code, &saved_handlers->action, 0);
86a5659e
JB
612 saved_handlers++;
613 }
614}
615\f
4a4bbad2 616#ifdef USABLE_SIGIO
1fa53021 617static int old_fcntl_flags[MAXDESC];
4a4bbad2 618#endif
86a5659e 619
08633194 620void
971de7fb 621init_sigio (int fd)
86a5659e 622{
4a4bbad2 623#ifdef USABLE_SIGIO
819b8f00
KL
624 old_fcntl_flags[fd] = fcntl (fd, F_GETFL, 0) & ~FASYNC;
625 fcntl (fd, F_SETFL, old_fcntl_flags[fd] | FASYNC);
23dab951 626 interrupts_deferred = 0;
4a4bbad2 627#endif
86a5659e
JB
628}
629
604efe86 630static void
971de7fb 631reset_sigio (int fd)
86a5659e 632{
4a4bbad2 633#ifdef USABLE_SIGIO
819b8f00 634 fcntl (fd, F_SETFL, old_fcntl_flags[fd]);
4d553a13 635#endif
86a5659e
JB
636}
637
08633194 638void
971de7fb 639request_sigio (void)
86a5659e 640{
4a4bbad2 641#ifdef USABLE_SIGIO
2fe28299
PE
642 sigset_t unblocked;
643
6bbba5a6 644 if (noninteractive)
23dab951
RS
645 return;
646
2fe28299 647 sigemptyset (&unblocked);
4a4bbad2 648# ifdef SIGWINCH
2fe28299 649 sigaddset (&unblocked, SIGWINCH);
4a4bbad2 650# endif
2fe28299
PE
651 sigaddset (&unblocked, SIGIO);
652 pthread_sigmask (SIG_UNBLOCK, &unblocked, 0);
86a5659e
JB
653
654 interrupts_deferred = 0;
4a4bbad2 655#endif
86a5659e
JB
656}
657
08633194 658void
0a125897 659unrequest_sigio (void)
cf84bb53 660{
4a4bbad2 661#ifdef USABLE_SIGIO
2fe28299
PE
662 sigset_t blocked;
663
6bbba5a6
KL
664 if (noninteractive)
665 return;
666
2fe28299 667 sigemptyset (&blocked);
4a4bbad2 668# ifdef SIGWINCH
2fe28299 669 sigaddset (&blocked, SIGWINCH);
4a4bbad2 670# endif
2fe28299
PE
671 sigaddset (&blocked, SIGIO);
672 pthread_sigmask (SIG_BLOCK, &blocked, 0);
86a5659e 673 interrupts_deferred = 1;
4a4bbad2 674#endif
86a5659e 675}
177c0ea7 676
08633194 677void
4a4bbad2 678ignore_sigio (void)
86a5659e 679{
4a4bbad2
PE
680#ifdef USABLE_SIGIO
681 signal (SIGIO, SIG_IGN);
682#endif
86a5659e 683}
feb67dfe 684
9ae8f997 685\f
322aea6d
PE
686/* Saving and restoring the process group of Emacs's terminal. */
687
688/* The process group of which Emacs was a member when it initially
689 started.
690
691 If Emacs was in its own process group (i.e. inherited_pgroup ==
692 getpid ()), then we know we're running under a shell with job
693 control (Emacs would never be run as part of a pipeline).
694 Everything is fine.
695
696 If Emacs was not in its own process group, then we know we're
697 running under a shell (or a caller) that doesn't know how to
698 separate itself from Emacs (like sh). Emacs must be in its own
699 process group in order to receive SIGIO correctly. In this
700 situation, we put ourselves in our own pgroup, forcibly set the
701 tty's pgroup to our pgroup, and make sure to restore and reinstate
702 the tty's pgroup just like any other terminal setting. If
703 inherited_group was not the tty's pgroup, then we'll get a
704 SIGTTmumble when we try to change the tty's pgroup, and a CONT if
705 it goes foreground in the future, which is what should happen. */
706
707static pid_t inherited_pgroup;
708
709void
710init_foreground_group (void)
711{
712 pid_t pgrp = EMACS_GETPGRP (0);
713 inherited_pgroup = getpid () == pgrp ? 0 : pgrp;
714}
715
716/* Safely set a controlling terminal FD's process group to PGID.
717 If we are not in the foreground already, POSIX requires tcsetpgrp
718 to deliver a SIGTTOU signal, which would stop us. This is an
719 annoyance, so temporarily ignore the signal.
720
721 In practice, platforms lacking SIGTTOU also lack tcsetpgrp, so
722 skip all this unless SIGTTOU is defined. */
723static void
724tcsetpgrp_without_stopping (int fd, pid_t pgid)
725{
726#ifdef SIGTTOU
727 signal_handler_t handler;
728 block_input ();
729 handler = signal (SIGTTOU, SIG_IGN);
730 tcsetpgrp (fd, pgid);
731 signal (SIGTTOU, handler);
732 unblock_input ();
733#endif
734}
735
736/* Split off the foreground process group to Emacs alone. When we are
737 in the foreground, but not started in our own process group,
738 redirect the tty device handle FD to point to our own process
739 group. FD must be the file descriptor of the controlling tty. */
740static void
741narrow_foreground_group (int fd)
742{
743 if (inherited_pgroup && setpgid (0, 0) == 0)
744 tcsetpgrp_without_stopping (fd, getpid ());
745}
746
747/* Set the tty to our original foreground group. */
748static void
749widen_foreground_group (int fd)
750{
751 if (inherited_pgroup && setpgid (0, inherited_pgroup) == 0)
752 tcsetpgrp_without_stopping (fd, inherited_pgroup);
753}
754\f
68936329
JB
755/* Getting and setting emacs_tty structures. */
756
757/* Set *TC to the parameters associated with the terminal FD.
758 Return zero if all's well, or -1 if we ran into an error we
759 couldn't deal with. */
760int
971de7fb 761emacs_get_tty (int fd, struct emacs_tty *settings)
68936329
JB
762{
763 /* Retrieve the primary parameters - baud rate, character size, etcetera. */
a7ebc409 764#ifndef DOS_NT
68936329 765 /* We have those nifty POSIX tcmumbleattr functions. */
72af86bd 766 memset (&settings->main, 0, sizeof (settings->main));
68936329
JB
767 if (tcgetattr (fd, &settings->main) < 0)
768 return -1;
68936329
JB
769#endif
770
771 /* We have survived the tempest. */
772 return 0;
773}
774
775
776/* Set the parameters of the tty on FD according to the contents of
394049ec 777 *SETTINGS. If FLUSHP is non-zero, we discard input.
68936329 778 Return 0 if all went well, and -1 if anything failed. */
394049ec 779
68936329 780int
971de7fb 781emacs_set_tty (int fd, struct emacs_tty *settings, int flushp)
68936329
JB
782{
783 /* Set the primary parameters - baud rate, character size, etcetera. */
a7ebc409 784#ifndef DOS_NT
e6cc3307 785 int i;
68936329
JB
786 /* We have those nifty POSIX tcmumbleattr functions.
787 William J. Smith <wjs@wiis.wang.com> writes:
c4ea52a6 788 "POSIX 1003.1 defines tcsetattr to return success if it was
68936329
JB
789 able to perform any of the requested actions, even if some
790 of the requested actions could not be performed.
791 We must read settings back to ensure tty setup properly.
792 AIX requires this to keep tty from hanging occasionally." */
eb8c3be9 793 /* This make sure that we don't loop indefinitely in here. */
e6cc3307 794 for (i = 0 ; i < 10 ; i++)
394049ec 795 if (tcsetattr (fd, flushp ? TCSAFLUSH : TCSADRAIN, &settings->main) < 0)
68936329
JB
796 {
797 if (errno == EINTR)
798 continue;
799 else
800 return -1;
801 }
802 else
803 {
804 struct termios new;
805
72af86bd 806 memset (&new, 0, sizeof (new));
68936329
JB
807 /* Get the current settings, and see if they're what we asked for. */
808 tcgetattr (fd, &new);
e6cc3307
RS
809 /* We cannot use memcmp on the whole structure here because under
810 * aix386 the termios structure has some reserved field that may
811 * not be filled in.
812 */
813 if ( new.c_iflag == settings->main.c_iflag
814 && new.c_oflag == settings->main.c_oflag
815 && new.c_cflag == settings->main.c_cflag
816 && new.c_lflag == settings->main.c_lflag
c4ea52a6 817 && memcmp (new.c_cc, settings->main.c_cc, NCCS) == 0)
68936329 818 break;
e6cc3307
RS
819 else
820 continue;
68936329 821 }
68936329 822#endif
177c0ea7 823
68936329
JB
824 /* We have survived the tempest. */
825 return 0;
826}
827
828\f
86a5659e
JB
829
830#ifdef F_SETOWN
1fa53021 831static int old_fcntl_owner[MAXDESC];
86a5659e
JB
832#endif /* F_SETOWN */
833
86a5659e
JB
834/* This may also be defined in stdio,
835 but if so, this does no harm,
836 and using the same name avoids wasting the other one's space. */
837
9d9a7716 838#if defined (USG)
86a5659e
JB
839unsigned char _sobuf[BUFSIZ+8];
840#else
841char _sobuf[BUFSIZ];
842#endif
177c0ea7 843
da8e1115
KL
844/* Initialize the terminal mode on all tty devices that are currently
845 open. */
846
08633194 847void
28d440ab
KL
848init_all_sys_modes (void)
849{
28d7d09f 850 struct tty_display_info *tty;
16c290d8 851 for (tty = tty_list; tty; tty = tty->next)
28d440ab 852 init_sys_modes (tty);
28d440ab
KL
853}
854
da8e1115
KL
855/* Initialize the terminal mode on the given tty device. */
856
28d440ab 857void
971de7fb 858init_sys_modes (struct tty_display_info *tty_out)
86a5659e 859{
91bac16a 860 struct emacs_tty tty;
e112cc37 861 Lisp_Object terminal;
91bac16a 862
4ec5cb58
RS
863 Vtty_erase_char = Qnil;
864
86a5659e
JB
865 if (noninteractive)
866 return;
867
0b0d3e0b
KL
868 if (!tty_out->output)
869 return; /* The tty is suspended. */
cf84bb53 870
322aea6d
PE
871 narrow_foreground_group (fileno (tty_out->input));
872
2246281f 873 if (! tty_out->old_tty)
38182d90 874 tty_out->old_tty = xmalloc (sizeof *tty_out->old_tty);
cf84bb53 875
12e610e8 876 emacs_get_tty (fileno (tty_out->input), tty_out->old_tty);
23dab951 877
2246281f 878 tty = *tty_out->old_tty;
86a5659e 879
a7ebc409 880#if !defined (DOS_NT)
2246281f 881 XSETINT (Vtty_erase_char, tty.main.c_cc[VERASE]);
4ec5cb58 882
2246281f
KL
883 tty.main.c_iflag |= (IGNBRK); /* Ignore break condition */
884 tty.main.c_iflag &= ~ICRNL; /* Disable map of CR to NL on input */
7f371164
RS
885#ifdef INLCR /* I'm just being cautious,
886 since I can't check how widespread INLCR is--rms. */
2246281f 887 tty.main.c_iflag &= ~INLCR; /* Disable map of NL to CR on input */
7f371164 888#endif
86a5659e 889#ifdef ISTRIP
2246281f 890 tty.main.c_iflag &= ~ISTRIP; /* don't strip 8th bit on input */
86a5659e 891#endif
2246281f
KL
892 tty.main.c_lflag &= ~ECHO; /* Disable echo */
893 tty.main.c_lflag &= ~ICANON; /* Disable erase/kill processing */
e2b40c23 894#ifdef IEXTEN
2246281f 895 tty.main.c_lflag &= ~IEXTEN; /* Disable other editing characters. */
e2b40c23 896#endif
2246281f
KL
897 tty.main.c_lflag |= ISIG; /* Enable signals */
898 if (tty_out->flow_control)
899 {
900 tty.main.c_iflag |= IXON; /* Enable start/stop output control */
86a5659e 901#ifdef IXANY
2246281f 902 tty.main.c_iflag &= ~IXANY;
86a5659e 903#endif /* IXANY */
2246281f
KL
904 }
905 else
906 tty.main.c_iflag &= ~IXON; /* Disable start/stop output control */
907 tty.main.c_oflag &= ~ONLCR; /* Disable map of NL to CR-NL
908 on output */
909 tty.main.c_oflag &= ~TAB3; /* Disable tab expansion */
86a5659e 910#ifdef CS8
2246281f
KL
911 if (tty_out->meta_key)
912 {
913 tty.main.c_cflag |= CS8; /* allow 8th bit on input */
914 tty.main.c_cflag &= ~PARENB;/* Don't check parity */
915 }
86a5659e 916#endif
e112cc37
ET
917
918 XSETTERMINAL(terminal, tty_out->terminal);
919 if (!NILP (Fcontrolling_tty_p (terminal)))
2246281f
KL
920 {
921 tty.main.c_cc[VINTR] = quit_char; /* C-g (usually) gives SIGINT */
922 /* Set up C-g for both SIGQUIT and SIGINT.
923 We don't know which we will get, but we handle both alike
924 so which one it really gives us does not matter. */
925 tty.main.c_cc[VQUIT] = quit_char;
926 }
927 else
928 {
929 /* We normally don't get interrupt or quit signals from tty
930 devices other than our controlling terminal; therefore,
931 we must handle C-g as normal input. Unfortunately, this
932 means that the interrupt and quit feature must be
933 disabled on secondary ttys, or we would not even see the
934 keypress.
cf84bb53 935
2246281f
KL
936 Note that even though emacsclient could have special code
937 to pass SIGINT to Emacs, we should _not_ enable
938 interrupt/quit keys for emacsclient frames. This means
939 that we can't break out of loops in C code from a
940 secondary tty frame, but we can always decide what
941 display the C-g came from, which is more important from a
942 usability point of view. (Consider the case when two
943 people work together using the same Emacs instance.) */
944 tty.main.c_cc[VINTR] = CDISABLE;
945 tty.main.c_cc[VQUIT] = CDISABLE;
946 }
947 tty.main.c_cc[VMIN] = 1; /* Input should wait for at least 1 char */
948 tty.main.c_cc[VTIME] = 0; /* no matter how long that takes. */
86a5659e 949#ifdef VSWTCH
2246281f 950 tty.main.c_cc[VSWTCH] = CDISABLE; /* Turn off shell layering use
91bac16a 951 of C-z */
86a5659e 952#endif /* VSWTCH */
cf84bb53 953
86a5659e 954#ifdef VSUSP
a7ebc409 955 tty.main.c_cc[VSUSP] = CDISABLE; /* Turn off handling of C-z. */
86a5659e
JB
956#endif /* VSUSP */
957#ifdef V_DSUSP
a7ebc409 958 tty.main.c_cc[V_DSUSP] = CDISABLE; /* Turn off handling of C-y. */
86a5659e 959#endif /* V_DSUSP */
e2b40c23 960#ifdef VDSUSP /* Some systems have VDSUSP, some have V_DSUSP. */
2246281f 961 tty.main.c_cc[VDSUSP] = CDISABLE;
e2b40c23 962#endif /* VDSUSP */
92c995de 963#ifdef VLNEXT
2246281f 964 tty.main.c_cc[VLNEXT] = CDISABLE;
92c995de
RS
965#endif /* VLNEXT */
966#ifdef VREPRINT
2246281f 967 tty.main.c_cc[VREPRINT] = CDISABLE;
92c995de
RS
968#endif /* VREPRINT */
969#ifdef VWERASE
2246281f 970 tty.main.c_cc[VWERASE] = CDISABLE;
92c995de
RS
971#endif /* VWERASE */
972#ifdef VDISCARD
2246281f 973 tty.main.c_cc[VDISCARD] = CDISABLE;
92c995de 974#endif /* VDISCARD */
c179a6d1 975
2246281f
KL
976 if (tty_out->flow_control)
977 {
421dd92f 978#ifdef VSTART
2246281f 979 tty.main.c_cc[VSTART] = '\021';
421dd92f
RS
980#endif /* VSTART */
981#ifdef VSTOP
2246281f 982 tty.main.c_cc[VSTOP] = '\023';
421dd92f 983#endif /* VSTOP */
2246281f
KL
984 }
985 else
986 {
c179a6d1 987#ifdef VSTART
2246281f 988 tty.main.c_cc[VSTART] = CDISABLE;
c179a6d1
RS
989#endif /* VSTART */
990#ifdef VSTOP
2246281f 991 tty.main.c_cc[VSTOP] = CDISABLE;
c179a6d1 992#endif /* VSTOP */
2246281f 993 }
c179a6d1 994
86a5659e 995#ifdef AIX
f5272227
KL
996 tty.main.c_cc[VSTRT] = CDISABLE;
997 tty.main.c_cc[VSTOP] = CDISABLE;
998 tty.main.c_cc[VSUSP] = CDISABLE;
999 tty.main.c_cc[VDSUSP] = CDISABLE;
2246281f
KL
1000 if (tty_out->flow_control)
1001 {
ac567c95 1002#ifdef VSTART
2246281f 1003 tty.main.c_cc[VSTART] = '\021';
ac567c95
RS
1004#endif /* VSTART */
1005#ifdef VSTOP
2246281f 1006 tty.main.c_cc[VSTOP] = '\023';
ac567c95 1007#endif /* VSTOP */
2246281f
KL
1008 }
1009 /* Also, PTY overloads NUL and BREAK.
1010 don't ignore break, but don't signal either, so it looks like NUL.
1011 This really serves a purpose only if running in an XTERM window
1012 or via TELNET or the like, but does no harm elsewhere. */
1013 tty.main.c_iflag &= ~IGNBRK;
1014 tty.main.c_iflag &= ~BRKINT;
86a5659e 1015#endif
fe03522b 1016#endif /* not DOS_NT */
cf84bb53 1017
207bdbdb 1018#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida, MW Aug 1993 */
2246281f
KL
1019 if (!tty_out->term_initted)
1020 internal_terminal_init ();
4e389d32 1021 dos_ttraw (tty_out);
207bdbdb 1022#endif
91bac16a 1023
12e610e8 1024 emacs_set_tty (fileno (tty_out->input), &tty, 0);
86a5659e 1025
2246281f
KL
1026 /* This code added to insure that, if flow-control is not to be used,
1027 we have an unlocked terminal at the start. */
91bac16a 1028
86a5659e 1029#ifdef TCXONC
0b0d3e0b 1030 if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TCXONC, 1);
86a5659e 1031#endif
86a5659e 1032#ifdef TIOCSTART
0b0d3e0b 1033 if (!tty_out->flow_control) ioctl (fileno (tty_out->input), TIOCSTART, 0);
86a5659e 1034#endif
86a5659e 1035
a7ebc409 1036#if !defined (DOS_NT)
51417996 1037#ifdef TCOON
0b0d3e0b 1038 if (!tty_out->flow_control) tcflow (fileno (tty_out->input), TCOON);
d228f207 1039#endif
51417996 1040#endif
d228f207 1041
86a5659e 1042#ifdef F_SETFL
eb8c3be9 1043#ifdef F_GETOWN /* F_SETFL does not imply existence of F_GETOWN */
2246281f 1044 if (interrupt_input)
86a5659e 1045 {
0b0d3e0b
KL
1046 old_fcntl_owner[fileno (tty_out->input)] =
1047 fcntl (fileno (tty_out->input), F_GETOWN, 0);
1048 fcntl (fileno (tty_out->input), F_SETOWN, getpid ());
1049 init_sigio (fileno (tty_out->input));
7e5a23bd 1050#ifdef HAVE_GPM
75a8734b 1051 if (gpm_tty == tty_out)
3e748bcb 1052 {
75a8734b 1053 /* Arrange for mouse events to give us SIGIO signals. */
3e748bcb 1054 fcntl (gpm_fd, F_SETOWN, getpid ());
57669cf1 1055 fcntl (gpm_fd, F_SETFL, fcntl (gpm_fd, F_GETFL, 0) | O_NONBLOCK);
3e748bcb
NR
1056 init_sigio (gpm_fd);
1057 }
7e5a23bd 1058#endif /* HAVE_GPM */
86a5659e
JB
1059 }
1060#endif /* F_GETOWN */
1061#endif /* F_SETFL */
1062
86a5659e
JB
1063#ifdef _IOFBF
1064 /* This symbol is defined on recent USG systems.
1065 Someone says without this call USG won't really buffer the file
1066 even with a call to setbuf. */
0b0d3e0b 1067 setvbuf (tty_out->output, (char *) _sobuf, _IOFBF, sizeof _sobuf);
86a5659e 1068#else
0b0d3e0b 1069 setbuf (tty_out->output, (char *) _sobuf);
86a5659e 1070#endif
4d553a13 1071
69fb5031
JR
1072 if (tty_out->terminal->set_terminal_modes_hook)
1073 tty_out->terminal->set_terminal_modes_hook (tty_out->terminal);
4b311aaf 1074
9628b887
KL
1075 if (!tty_out->term_initted)
1076 {
1077 Lisp_Object tail, frame;
1078 FOR_EACH_FRAME (tail, frame)
1079 {
daf01701 1080 /* XXX This needs to be revised. */
9628b887
KL
1081 if (FRAME_TERMCAP_P (XFRAME (frame))
1082 && FRAME_TTY (XFRAME (frame)) == tty_out)
1083 init_frame_faces (XFRAME (frame));
1084 }
1085 }
045942b2 1086
9628b887 1087 if (tty_out->term_initted && no_redraw_on_reenter)
86a5659e 1088 {
855a0da7
SM
1089 /* We used to call "direct_output_forward_char(0)" here,
1090 but it's not clear why, since it may not do anything anyway. */
86a5659e
JB
1091 }
1092 else
1093 {
9628b887 1094 Lisp_Object tail, frame;
0137dbf7 1095 frame_garbaged = 1;
9628b887
KL
1096 FOR_EACH_FRAME (tail, frame)
1097 {
7ab98847
EZ
1098 if ((FRAME_TERMCAP_P (XFRAME (frame))
1099 || FRAME_MSDOS_P (XFRAME (frame)))
9628b887
KL
1100 && FRAME_TTY (XFRAME (frame)) == tty_out)
1101 FRAME_GARBAGED_P (XFRAME (frame)) = 1;
1102 }
86a5659e 1103 }
91bac16a 1104
9628b887 1105 tty_out->term_initted = 1;
86a5659e
JB
1106}
1107
1108/* Return nonzero if safe to use tabs in output.
1109 At the time this is called, init_sys_modes has not been done yet. */
177c0ea7 1110
dfcf069d 1111int
16c290d8 1112tabs_safe_p (int fd)
86a5659e 1113{
6548cf00 1114 struct emacs_tty etty;
91bac16a 1115
12e610e8
DN
1116 emacs_get_tty (fd, &etty);
1117#ifndef DOS_NT
1118#ifdef TABDLY
1119 return ((etty.main.c_oflag & TABDLY) != TAB3);
1120#else /* not TABDLY */
1121 return 1;
1122#endif /* not TABDLY */
1123#else /* DOS_NT */
1124 return 0;
1125#endif /* DOS_NT */
86a5659e 1126}
73d5358f 1127\f
86a5659e 1128/* Get terminal size from system.
73d5358f
RS
1129 Store number of lines into *HEIGHTP and width into *WIDTHP.
1130 We store 0 if there's no valid information. */
86a5659e 1131
08633194 1132void
16c290d8 1133get_tty_size (int fd, int *widthp, int *heightp)
86a5659e 1134{
e16e55d4 1135#if defined TIOCGWINSZ
91bac16a
JB
1136
1137 /* BSD-style. */
86a5659e 1138 struct winsize size;
91bac16a 1139
16c290d8 1140 if (ioctl (fd, TIOCGWINSZ, &size) == -1)
91bac16a
JB
1141 *widthp = *heightp = 0;
1142 else
1143 {
1144 *widthp = size.ws_col;
1145 *heightp = size.ws_row;
1146 }
1147
e16e55d4 1148#elif defined TIOCGSIZE
91bac16a
JB
1149
1150 /* SunOS - style. */
177c0ea7 1151 struct ttysize size;
91bac16a 1152
16c290d8 1153 if (ioctl (fd, TIOCGSIZE, &size) == -1)
91bac16a
JB
1154 *widthp = *heightp = 0;
1155 else
1156 {
1157 *widthp = size.ts_cols;
1158 *heightp = size.ts_lines;
1159 }
1160
e16e55d4
JB
1161#elif defined WINDOWSNT
1162
1163 CONSOLE_SCREEN_BUFFER_INFO info;
1164 if (GetConsoleScreenBufferInfo (GetStdHandle (STD_OUTPUT_HANDLE), &info))
1165 {
1166 *widthp = info.srWindow.Right - info.srWindow.Left + 1;
1167 *heightp = info.srWindow.Bottom - info.srWindow.Top + 1;
1168 }
1169 else
1170 *widthp = *heightp = 0;
1171
1172#elif defined MSDOS
1173
207bdbdb
RS
1174 *widthp = ScreenCols ();
1175 *heightp = ScreenRows ();
e16e55d4 1176
86a5659e 1177#else /* system doesn't know size */
e16e55d4 1178
86a5659e
JB
1179 *widthp = 0;
1180 *heightp = 0;
e16e55d4 1181
207bdbdb 1182#endif
86a5659e 1183}
91bac16a 1184
73d5358f
RS
1185/* Set the logical window size associated with descriptor FD
1186 to HEIGHT and WIDTH. This is used mainly with ptys. */
1187
1188int
971de7fb 1189set_window_size (int fd, int height, int width)
73d5358f
RS
1190{
1191#ifdef TIOCSWINSZ
1192
1193 /* BSD-style. */
1194 struct winsize size;
1195 size.ws_row = height;
1196 size.ws_col = width;
1197
1198 if (ioctl (fd, TIOCSWINSZ, &size) == -1)
1199 return 0; /* error */
1200 else
1201 return 1;
1202
1203#else
1204#ifdef TIOCSSIZE
1205
1206 /* SunOS - style. */
177c0ea7 1207 struct ttysize size;
73d5358f
RS
1208 size.ts_lines = height;
1209 size.ts_cols = width;
1210
1211 if (ioctl (fd, TIOCGSIZE, &size) == -1)
1212 return 0;
1213 else
1214 return 1;
1215#else
1216 return -1;
1217#endif /* not SunOS-style */
1218#endif /* not BSD-style */
1219}
1220
86a5659e 1221\f
da8e1115
KL
1222
1223/* Prepare all terminal devices for exiting Emacs. */
1224
28d440ab
KL
1225void
1226reset_all_sys_modes (void)
1227{
28d7d09f 1228 struct tty_display_info *tty;
16c290d8 1229 for (tty = tty_list; tty; tty = tty->next)
28d440ab 1230 reset_sys_modes (tty);
28d440ab
KL
1231}
1232
0a125897 1233/* Prepare the terminal for closing it; move the cursor to the
0137dbf7 1234 bottom of the frame, turn off interrupt-driven I/O, etc. */
da8e1115 1235
08633194 1236void
971de7fb 1237reset_sys_modes (struct tty_display_info *tty_out)
86a5659e
JB
1238{
1239 if (noninteractive)
1240 {
1241 fflush (stdout);
1242 return;
1243 }
9628b887 1244 if (!tty_out->term_initted)
86a5659e 1245 return;
da8e1115 1246
0b0d3e0b
KL
1247 if (!tty_out->output)
1248 return; /* The tty is suspended. */
cf84bb53 1249
da8e1115
KL
1250 /* Go to and clear the last line of the terminal. */
1251
0a125897 1252 cmgoto (tty_out, FrameRows (tty_out) - 1, 0);
cf84bb53 1253
da8e1115
KL
1254 /* Code adapted from tty_clear_end_of_line. */
1255 if (tty_out->TS_clr_line)
1256 {
1257 emacs_tputs (tty_out, tty_out->TS_clr_line, 1, cmputc);
1258 }
1259 else
1260 { /* have to do it the hard way */
1261 int i;
ed8dad6b 1262 tty_turn_off_insert (tty_out);
cf84bb53 1263
da8e1115 1264 for (i = curX (tty_out); i < FrameCols (tty_out) - 1; i++)
0b0d3e0b
KL
1265 {
1266 fputc (' ', tty_out->output);
1267 }
da8e1115 1268 }
cf84bb53 1269
0a125897 1270 cmgoto (tty_out, FrameRows (tty_out) - 1, 0);
819b8f00 1271 fflush (tty_out->output);
cf84bb53 1272
69fb5031
JR
1273 if (tty_out->terminal->reset_terminal_modes_hook)
1274 tty_out->terminal->reset_terminal_modes_hook (tty_out->terminal);
2f98e6e3 1275
2a633456 1276#ifdef BSD_SYSTEM
86a5659e 1277 /* Avoid possible loss of output when changing terminal modes. */
0b0d3e0b 1278 fsync (fileno (tty_out->output));
86a5659e 1279#endif
91bac16a 1280
86a5659e 1281#ifdef F_SETFL
eb8c3be9 1282#ifdef F_SETOWN /* F_SETFL does not imply existence of F_SETOWN */
86a5659e
JB
1283 if (interrupt_input)
1284 {
0b0d3e0b
KL
1285 reset_sigio (fileno (tty_out->input));
1286 fcntl (fileno (tty_out->input), F_SETOWN,
1287 old_fcntl_owner[fileno (tty_out->input)]);
86a5659e
JB
1288 }
1289#endif /* F_SETOWN */
a6b00318 1290#ifdef O_NDELAY
0b0d3e0b
KL
1291 fcntl (fileno (tty_out->input), F_SETFL,
1292 fcntl (fileno (tty_out->input), F_GETFL, 0) & ~O_NDELAY);
a6b00318 1293#endif
86a5659e 1294#endif /* F_SETFL */
91bac16a 1295
fca177d4 1296 if (tty_out->old_tty)
12e610e8 1297 while (emacs_set_tty (fileno (tty_out->input),
fca177d4 1298 tty_out->old_tty, 0) < 0 && errno == EINTR)
7e32a4fb 1299 ;
86a5659e 1300
207bdbdb
RS
1301#ifdef MSDOS /* Demacs 1.1.2 91/10/20 Manabu Higashida */
1302 dos_ttcooked ();
1303#endif
1304
322aea6d 1305 widen_foreground_group (fileno (tty_out->input));
86a5659e
JB
1306}
1307\f
1308#ifdef HAVE_PTYS
1309
1310/* Set up the proper status flags for use of a pty. */
1311
08633194 1312void
971de7fb 1313setup_pty (int fd)
86a5659e
JB
1314{
1315 /* I'm told that TOICREMOTE does not mean control chars
1316 "can't be sent" but rather that they don't have
1317 input-editing or signaling effects.
1318 That should be good, because we have other ways
1319 to do those things in Emacs.
1320 However, telnet mode seems not to work on 4.2.
1321 So TIOCREMOTE is turned off now. */
1322
1323 /* Under hp-ux, if TIOCREMOTE is turned on, some calls
1324 will hang. In particular, the "timeout" feature (which
1325 causes a read to return if there is no data available)
1326 does this. Also it is known that telnet mode will hang
1327 in such a way that Emacs must be stopped (perhaps this
1328 is the same problem).
177c0ea7 1329
86a5659e
JB
1330 If TIOCREMOTE is turned off, then there is a bug in
1331 hp-ux which sometimes loses data. Apparently the
1332 code which blocks the master process when the internal
1333 buffer fills up does not work. Other than this,
1334 though, everything else seems to work fine.
177c0ea7 1335
86a5659e
JB
1336 Since the latter lossage is more benign, we may as well
1337 lose that way. -- cph */
1338#ifdef FIONBIO
5e617bc2 1339#if defined (UNIX98_PTYS)
86a5659e
JB
1340 {
1341 int on = 1;
1342 ioctl (fd, FIONBIO, &on);
1343 }
1344#endif
1345#endif
86a5659e
JB
1346}
1347#endif /* HAVE_PTYS */
1348\f
f8a80313
RS
1349#ifdef HAVE_SOCKETS
1350#include <sys/socket.h>
1351#include <netdb.h>
1352#endif /* HAVE_SOCKETS */
f8a80313 1353
8581cd64
KH
1354#ifdef TRY_AGAIN
1355#ifndef HAVE_H_ERRNO
1356extern int h_errno;
1357#endif
1358#endif /* TRY_AGAIN */
1359
c0c86835 1360void
971de7fb 1361init_system_name (void)
86a5659e 1362{
210b2b4f 1363#ifndef HAVE_GETHOSTNAME
c0c86835
KH
1364 struct utsname uts;
1365 uname (&uts);
1366 Vsystem_name = build_string (uts.nodename);
67004ffb 1367#else /* HAVE_GETHOSTNAME */
cc6e7269 1368 unsigned int hostname_size = 256;
38182d90 1369 char *hostname = alloca (hostname_size);
c0c86835
KH
1370
1371 /* Try to get the host name; if the buffer is too short, try
1372 again. Apparently, the only indication gethostname gives of
1373 whether the buffer was large enough is the presence or absence
1374 of a '\0' in the string. Eech. */
1375 for (;;)
1376 {
1377 gethostname (hostname, hostname_size - 1);
1378 hostname[hostname_size - 1] = '\0';
1379
1380 /* Was the buffer large enough for the '\0'? */
1381 if (strlen (hostname) < hostname_size - 1)
1382 break;
1383
1384 hostname_size <<= 1;
38182d90 1385 hostname = alloca (hostname_size);
c0c86835 1386 }
67004ffb 1387#ifdef HAVE_SOCKETS
c0c86835
KH
1388 /* Turn the hostname into the official, fully-qualified hostname.
1389 Don't do this if we're going to dump; this can confuse system
1390 libraries on some machines and make the dumped emacs core dump. */
67004ffb 1391#ifndef CANNOT_DUMP
c0c86835 1392 if (initialized)
67004ffb 1393#endif /* not CANNOT_DUMP */
8966b757 1394 if (! strchr (hostname, '.'))
960d894c 1395 {
960d894c 1396 int count;
3d66b985
JD
1397#ifdef HAVE_GETADDRINFO
1398 struct addrinfo *res;
1399 struct addrinfo hints;
1400 int ret;
1401
cf84bb53 1402 memset (&hints, 0, sizeof (hints));
3d66b985
JD
1403 hints.ai_socktype = SOCK_STREAM;
1404 hints.ai_flags = AI_CANONNAME;
1405
960d894c
KH
1406 for (count = 0;; count++)
1407 {
3d66b985
JD
1408 if ((ret = getaddrinfo (hostname, NULL, &hints, &res)) == 0
1409 || ret != EAI_AGAIN)
1410 break;
1411
1412 if (count >= 5)
1413 break;
1414 Fsleep_for (make_number (1), Qnil);
1415 }
1416
1417 if (ret == 0)
1418 {
1419 struct addrinfo *it = res;
1420 while (it)
1421 {
1422 char *fqdn = it->ai_canonname;
8966b757 1423 if (fqdn && strchr (fqdn, '.')
3d66b985
JD
1424 && strcmp (fqdn, "localhost.localdomain") != 0)
1425 break;
1426 it = it->ai_next;
1427 }
1428 if (it)
1429 {
1430 hostname = alloca (strlen (it->ai_canonname) + 1);
1431 strcpy (hostname, it->ai_canonname);
1432 }
1433 freeaddrinfo (res);
1434 }
1435#else /* !HAVE_GETADDRINFO */
1436 struct hostent *hp;
1437 for (count = 0;; count++)
1438 {
1439
e24f1d55 1440#ifdef TRY_AGAIN
960d894c 1441 h_errno = 0;
e24f1d55 1442#endif
960d894c 1443 hp = gethostbyname (hostname);
efa04277 1444#ifdef TRY_AGAIN
960d894c
KH
1445 if (! (hp == 0 && h_errno == TRY_AGAIN))
1446#endif
3d66b985 1447
960d894c 1448 break;
3d66b985 1449
960d894c
KH
1450 if (count >= 5)
1451 break;
1452 Fsleep_for (make_number (1), Qnil);
1453 }
3d66b985 1454
960d894c
KH
1455 if (hp)
1456 {
1457 char *fqdn = (char *) hp->h_name;
960d894c 1458
8966b757 1459 if (!strchr (fqdn, '.'))
960d894c
KH
1460 {
1461 /* We still don't have a fully qualified domain name.
1462 Try to find one in the list of alternate names */
1463 char **alias = hp->h_aliases;
923721f4 1464 while (*alias
8966b757 1465 && (!strchr (*alias, '.')
923721f4 1466 || !strcmp (*alias, "localhost.localdomain")))
960d894c
KH
1467 alias++;
1468 if (*alias)
1469 fqdn = *alias;
1470 }
1471 hostname = fqdn;
960d894c 1472 }
3d66b985 1473#endif /* !HAVE_GETADDRINFO */
960d894c 1474 }
67004ffb 1475#endif /* HAVE_SOCKETS */
c0c86835 1476 Vsystem_name = build_string (hostname);
67004ffb 1477#endif /* HAVE_GETHOSTNAME */
c0c86835
KH
1478 {
1479 unsigned char *p;
d5db4077 1480 for (p = SDATA (Vsystem_name); *p; p++)
c0c86835
KH
1481 if (*p == ' ' || *p == '\t')
1482 *p = '-';
1483 }
67004ffb 1484}
86a5659e 1485\f
1fa53021 1486sigset_t empty_mask;
86a5659e 1487
4d7e6e51
PE
1488static struct sigaction process_fatal_action;
1489
1490static int
1491emacs_sigaction_flags (void)
86a5659e 1492{
4d7e6e51 1493#ifdef SA_RESTART
0caaedb1
PE
1494 /* SA_RESTART causes interruptible functions with timeouts (e.g.,
1495 'select') to reset their timeout on some platforms (e.g.,
1496 HP-UX 11), which is not what we want. Also, when Emacs is
1497 interactive, we don't want SA_RESTART because we need to poll
275464e7 1498 for pending input so we need long-running syscalls to be interrupted
4d7e6e51
PE
1499 after a signal that sets pending_signals.
1500
1501 Non-interactive keyboard input goes through stdio, where we
1502 always want restartable system calls. */
ef874e3d 1503 if (noninteractive)
4d7e6e51 1504 return SA_RESTART;
e065a56e 1505#endif
4d7e6e51
PE
1506 return 0;
1507}
1508
1509/* Store into *ACTION a signal action suitable for Emacs, with handler
1510 HANDLER. */
1511void
1512emacs_sigaction_init (struct sigaction *action, signal_handler_t handler)
1513{
1514 sigemptyset (&action->sa_mask);
1515
1516 /* When handling a signal, block nonfatal system signals that are caught
1517 by Emacs. This makes race conditions less likely. */
1518 sigaddset (&action->sa_mask, SIGALRM);
1519#ifdef SIGCHLD
1520 sigaddset (&action->sa_mask, SIGCHLD);
1521#endif
1522#ifdef SIGDANGER
1523 sigaddset (&action->sa_mask, SIGDANGER);
1524#endif
d89460ed
PE
1525#ifdef PROFILER_CPU_SUPPORT
1526 sigaddset (&action->sa_mask, SIGPROF);
1527#endif
4d7e6e51
PE
1528#ifdef SIGWINCH
1529 sigaddset (&action->sa_mask, SIGWINCH);
1530#endif
1531 if (! noninteractive)
1532 {
1533 sigaddset (&action->sa_mask, SIGINT);
1534 sigaddset (&action->sa_mask, SIGQUIT);
1535#ifdef USABLE_SIGIO
1536 sigaddset (&action->sa_mask, SIGIO);
1537#endif
1538 }
1539
1540 if (! IEEE_FLOATING_POINT)
1541 sigaddset (&action->sa_mask, SIGFPE);
1542
1543 action->sa_handler = handler;
1544 action->sa_flags = emacs_sigaction_flags ();
86a5659e
JB
1545}
1546
20ef56db 1547#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
0caaedb1 1548static pthread_t main_thread;
20ef56db
PE
1549#endif
1550
4d7e6e51
PE
1551/* SIG has arrived at the current process. Deliver it to the main
1552 thread, which should handle it with HANDLER.
1553
1554 If we are on the main thread, handle the signal SIG with HANDLER.
20ef56db
PE
1555 Otherwise, redirect the signal to the main thread, blocking it from
1556 this thread. POSIX says any thread can receive a signal that is
1557 associated with a process, process group, or asynchronous event.
1558 On GNU/Linux that is not true, but for other systems (FreeBSD at
1559 least) it is. */
1560void
4d7e6e51 1561deliver_process_signal (int sig, signal_handler_t handler)
20ef56db
PE
1562{
1563 /* Preserve errno, to avoid race conditions with signal handlers that
1564 might change errno. Races can occur even in single-threaded hosts. */
1565 int old_errno = errno;
1566
1567 bool on_main_thread = true;
1568#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
1569 if (! pthread_equal (pthread_self (), main_thread))
1570 {
1571 sigset_t blocked;
1572 sigemptyset (&blocked);
1573 sigaddset (&blocked, sig);
1574 pthread_sigmask (SIG_BLOCK, &blocked, 0);
1575 pthread_kill (main_thread, sig);
1576 on_main_thread = false;
1577 }
1578#endif
1579 if (on_main_thread)
1580 handler (sig);
1581
1582 errno = old_errno;
1583}
4d7e6e51
PE
1584
1585/* Static location to save a fatal backtrace in a thread.
1586 FIXME: If two subsidiary threads fail simultaneously, the resulting
1587 backtrace may be garbage. */
1588enum { BACKTRACE_LIMIT_MAX = 500 };
1589static void *thread_backtrace_buffer[BACKTRACE_LIMIT_MAX + 1];
1590static int thread_backtrace_npointers;
1591
1592/* SIG has arrived at the current thread.
1593 If we are on the main thread, handle the signal SIG with HANDLER.
1594 Otherwise, this is a fatal error in the handling thread. */
1595static void
1596deliver_thread_signal (int sig, signal_handler_t handler)
1597{
1598 int old_errno = errno;
1599
1600#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
1601 if (! pthread_equal (pthread_self (), main_thread))
1602 {
1603 thread_backtrace_npointers
1604 = backtrace (thread_backtrace_buffer, BACKTRACE_LIMIT_MAX);
1605 sigaction (sig, &process_fatal_action, 0);
1606 pthread_kill (main_thread, sig);
1607
1608 /* Avoid further damage while the main thread is exiting. */
1609 while (1)
1610 sigsuspend (&empty_mask);
1611 }
1612#endif
1613
1614 handler (sig);
1615 errno = old_errno;
1616}
86a5659e 1617\f
aa1ba90e
PE
1618#if !HAVE_DECL_SYS_SIGLIST
1619# undef sys_siglist
c622b48f
PE
1620# ifdef _sys_siglist
1621# define sys_siglist _sys_siglist
1622# else
1623# define sys_siglist my_sys_siglist
aa1ba90e 1624static char const *sys_siglist[NSIG];
c622b48f
PE
1625# endif
1626#endif
1627
1628#ifdef _sys_nsig
1629# define sys_siglist_entries _sys_nsig
1630#else
1631# define sys_siglist_entries NSIG
ca9c0567
PE
1632#endif
1633
4d7e6e51
PE
1634/* Handle bus errors, invalid instruction, etc. */
1635static void
1636handle_fatal_signal (int sig)
1637{
9d4dcdc9 1638 terminate_due_to_signal (sig, 40);
4d7e6e51
PE
1639}
1640
1641static void
1642deliver_fatal_signal (int sig)
1643{
1644 deliver_process_signal (sig, handle_fatal_signal);
1645}
1646
1647static void
1648deliver_fatal_thread_signal (int sig)
1649{
1650 deliver_thread_signal (sig, handle_fatal_signal);
1651}
1652
1653static _Noreturn void
1654handle_arith_signal (int sig)
1655{
1656 pthread_sigmask (SIG_SETMASK, &empty_mask, 0);
1657 xsignal0 (Qarith_error);
1658}
1659
1660static void
1661deliver_arith_signal (int sig)
1662{
1663 deliver_thread_signal (sig, handle_arith_signal);
1664}
1665
1666/* Treat SIG as a terminating signal, unless it is already ignored and
1667 we are in --batch mode. Among other things, this makes nohup work. */
1668static void
1669maybe_fatal_sig (int sig)
1670{
1671 bool catch_sig = !noninteractive;
1672 if (!catch_sig)
1673 {
1674 struct sigaction old_action;
1675 sigaction (sig, 0, &old_action);
1676 catch_sig = old_action.sa_handler != SIG_IGN;
1677 }
1678 if (catch_sig)
1679 sigaction (sig, &process_fatal_action, 0);
1680}
1681
ca9c0567 1682void
4d7e6e51 1683init_signals (bool dumping)
ca9c0567 1684{
4d7e6e51
PE
1685 struct sigaction thread_fatal_action;
1686 struct sigaction action;
1687
ca9c0567 1688 sigemptyset (&empty_mask);
ca9c0567 1689
20ef56db
PE
1690#ifdef FORWARD_SIGNAL_TO_MAIN_THREAD
1691 main_thread = pthread_self ();
1692#endif
1693
c622b48f 1694#if !HAVE_DECL_SYS_SIGLIST && !defined _sys_siglist
ca9c0567
PE
1695 if (! initialized)
1696 {
ca9c0567 1697 sys_siglist[SIGABRT] = "Aborted";
ca9c0567
PE
1698# ifdef SIGAIO
1699 sys_siglist[SIGAIO] = "LAN I/O interrupt";
1700# endif
1701# ifdef SIGALRM
1702 sys_siglist[SIGALRM] = "Alarm clock";
1703# endif
1704# ifdef SIGBUS
1705 sys_siglist[SIGBUS] = "Bus error";
1706# endif
1707# ifdef SIGCLD
1708 sys_siglist[SIGCLD] = "Child status changed";
1709# endif
1710# ifdef SIGCHLD
1711 sys_siglist[SIGCHLD] = "Child status changed";
1712# endif
1713# ifdef SIGCONT
1714 sys_siglist[SIGCONT] = "Continued";
1715# endif
1716# ifdef SIGDANGER
1717 sys_siglist[SIGDANGER] = "Swap space dangerously low";
1718# endif
1719# ifdef SIGDGNOTIFY
1720 sys_siglist[SIGDGNOTIFY] = "Notification message in queue";
1721# endif
1722# ifdef SIGEMT
1723 sys_siglist[SIGEMT] = "Emulation trap";
1724# endif
ca9c0567 1725 sys_siglist[SIGFPE] = "Arithmetic exception";
ca9c0567
PE
1726# ifdef SIGFREEZE
1727 sys_siglist[SIGFREEZE] = "SIGFREEZE";
1728# endif
1729# ifdef SIGGRANT
1730 sys_siglist[SIGGRANT] = "Monitor mode granted";
1731# endif
1732# ifdef SIGHUP
1733 sys_siglist[SIGHUP] = "Hangup";
1734# endif
ca9c0567 1735 sys_siglist[SIGILL] = "Illegal instruction";
ca9c0567 1736 sys_siglist[SIGINT] = "Interrupt";
ca9c0567
PE
1737# ifdef SIGIO
1738 sys_siglist[SIGIO] = "I/O possible";
1739# endif
1740# ifdef SIGIOINT
1741 sys_siglist[SIGIOINT] = "I/O intervention required";
1742# endif
1743# ifdef SIGIOT
1744 sys_siglist[SIGIOT] = "IOT trap";
1745# endif
1746# ifdef SIGKILL
1747 sys_siglist[SIGKILL] = "Killed";
1748# endif
1749# ifdef SIGLOST
1750 sys_siglist[SIGLOST] = "Resource lost";
1751# endif
1752# ifdef SIGLWP
1753 sys_siglist[SIGLWP] = "SIGLWP";
1754# endif
1755# ifdef SIGMSG
1756 sys_siglist[SIGMSG] = "Monitor mode data available";
1757# endif
1758# ifdef SIGPHONE
1759 sys_siglist[SIGWIND] = "SIGPHONE";
1760# endif
1761# ifdef SIGPIPE
1762 sys_siglist[SIGPIPE] = "Broken pipe";
1763# endif
1764# ifdef SIGPOLL
1765 sys_siglist[SIGPOLL] = "Pollable event occurred";
1766# endif
1767# ifdef SIGPROF
1768 sys_siglist[SIGPROF] = "Profiling timer expired";
1769# endif
1770# ifdef SIGPTY
1771 sys_siglist[SIGPTY] = "PTY I/O interrupt";
1772# endif
1773# ifdef SIGPWR
1774 sys_siglist[SIGPWR] = "Power-fail restart";
1775# endif
1776# ifdef SIGQUIT
1777 sys_siglist[SIGQUIT] = "Quit";
1778# endif
1779# ifdef SIGRETRACT
40ba43b4 1780 sys_siglist[SIGRETRACT] = "Need to relinquish monitor mode";
ca9c0567
PE
1781# endif
1782# ifdef SIGSAK
1783 sys_siglist[SIGSAK] = "Secure attention";
1784# endif
ca9c0567 1785 sys_siglist[SIGSEGV] = "Segmentation violation";
ca9c0567
PE
1786# ifdef SIGSOUND
1787 sys_siglist[SIGSOUND] = "Sound completed";
1788# endif
1789# ifdef SIGSTOP
1790 sys_siglist[SIGSTOP] = "Stopped (signal)";
1791# endif
1792# ifdef SIGSTP
1793 sys_siglist[SIGSTP] = "Stopped (user)";
1794# endif
1795# ifdef SIGSYS
1796 sys_siglist[SIGSYS] = "Bad argument to system call";
1797# endif
ca9c0567 1798 sys_siglist[SIGTERM] = "Terminated";
ca9c0567
PE
1799# ifdef SIGTHAW
1800 sys_siglist[SIGTHAW] = "SIGTHAW";
1801# endif
1802# ifdef SIGTRAP
1803 sys_siglist[SIGTRAP] = "Trace/breakpoint trap";
1804# endif
1805# ifdef SIGTSTP
1806 sys_siglist[SIGTSTP] = "Stopped (user)";
1807# endif
1808# ifdef SIGTTIN
1809 sys_siglist[SIGTTIN] = "Stopped (tty input)";
1810# endif
1811# ifdef SIGTTOU
1812 sys_siglist[SIGTTOU] = "Stopped (tty output)";
1813# endif
1814# ifdef SIGURG
1815 sys_siglist[SIGURG] = "Urgent I/O condition";
1816# endif
1817# ifdef SIGUSR1
1818 sys_siglist[SIGUSR1] = "User defined signal 1";
1819# endif
1820# ifdef SIGUSR2
1821 sys_siglist[SIGUSR2] = "User defined signal 2";
1822# endif
1823# ifdef SIGVTALRM
1824 sys_siglist[SIGVTALRM] = "Virtual timer expired";
1825# endif
1826# ifdef SIGWAITING
1827 sys_siglist[SIGWAITING] = "Process's LWPs are blocked";
1828# endif
1829# ifdef SIGWINCH
1830 sys_siglist[SIGWINCH] = "Window size changed";
1831# endif
1832# ifdef SIGWIND
1833 sys_siglist[SIGWIND] = "SIGWIND";
1834# endif
1835# ifdef SIGXCPU
1836 sys_siglist[SIGXCPU] = "CPU time limit exceeded";
1837# endif
1838# ifdef SIGXFSZ
1839 sys_siglist[SIGXFSZ] = "File size limit exceeded";
1840# endif
1841 }
c622b48f 1842#endif /* !HAVE_DECL_SYS_SIGLIST && !_sys_siglist */
4d7e6e51
PE
1843
1844 /* Don't alter signal handlers if dumping. On some machines,
1845 changing signal handlers sets static data that would make signals
1846 fail to work right when the dumped Emacs is run. */
1847 if (dumping)
1848 return;
1849
1850 sigfillset (&process_fatal_action.sa_mask);
1851 process_fatal_action.sa_handler = deliver_fatal_signal;
62a1d661 1852 process_fatal_action.sa_flags = emacs_sigaction_flags ();
4d7e6e51
PE
1853
1854 sigfillset (&thread_fatal_action.sa_mask);
1855 thread_fatal_action.sa_handler = deliver_fatal_thread_signal;
1856 thread_fatal_action.sa_flags = process_fatal_action.sa_flags;
1857
1858 /* SIGINT may need special treatment on MS-Windows. See
1859 http://lists.gnu.org/archive/html/emacs-devel/2010-09/msg01062.html
1860 Please update the doc of kill-emacs, kill-emacs-hook, and
1861 NEWS if you change this. */
1862
1863 maybe_fatal_sig (SIGHUP);
1864 maybe_fatal_sig (SIGINT);
1865 maybe_fatal_sig (SIGTERM);
1866
1867 /* Emacs checks for write errors, so it can safely ignore SIGPIPE.
1868 However, in batch mode leave SIGPIPE alone, as that causes Emacs
1869 to behave more like typical batch applications do. */
1870 if (! noninteractive)
1871 signal (SIGPIPE, SIG_IGN);
1872
1873 sigaction (SIGQUIT, &process_fatal_action, 0);
1874 sigaction (SIGILL, &thread_fatal_action, 0);
1875 sigaction (SIGTRAP, &thread_fatal_action, 0);
1876
1877 /* Typically SIGFPE is thread-specific and is fatal, like SIGILL.
1878 But on a non-IEEE host SIGFPE can come from a trap in the Lisp
1879 interpreter's floating point operations, so treat SIGFPE as an
1880 arith-error if it arises in the main thread. */
1881 if (IEEE_FLOATING_POINT)
1882 sigaction (SIGFPE, &thread_fatal_action, 0);
1883 else
1884 {
1885 emacs_sigaction_init (&action, deliver_arith_signal);
1886 sigaction (SIGFPE, &action, 0);
1887 }
1888
1889#ifdef SIGUSR1
1890 add_user_signal (SIGUSR1, "sigusr1");
1891#endif
1892#ifdef SIGUSR2
1893 add_user_signal (SIGUSR2, "sigusr2");
1894#endif
1895 sigaction (SIGABRT, &thread_fatal_action, 0);
1896#ifdef SIGPRE
1897 sigaction (SIGPRE, &thread_fatal_action, 0);
1898#endif
1899#ifdef SIGORE
1900 sigaction (SIGORE, &thread_fatal_action, 0);
1901#endif
1902#ifdef SIGUME
1903 sigaction (SIGUME, &thread_fatal_action, 0);
1904#endif
1905#ifdef SIGDLK
1906 sigaction (SIGDLK, &process_fatal_action, 0);
1907#endif
1908#ifdef SIGCPULIM
1909 sigaction (SIGCPULIM, &process_fatal_action, 0);
1910#endif
1911#ifdef SIGIOT
1912 sigaction (SIGIOT, &thread_fatal_action, 0);
1913#endif
1914#ifdef SIGEMT
1915 sigaction (SIGEMT, &thread_fatal_action, 0);
1916#endif
1917#ifdef SIGBUS
1918 sigaction (SIGBUS, &thread_fatal_action, 0);
1919#endif
1920 sigaction (SIGSEGV, &thread_fatal_action, 0);
1921#ifdef SIGSYS
1922 sigaction (SIGSYS, &thread_fatal_action, 0);
1923#endif
1924 sigaction (SIGTERM, &process_fatal_action, 0);
1925#ifdef SIGPROF
d89460ed 1926 signal (SIGPROF, SIG_IGN);
4d7e6e51
PE
1927#endif
1928#ifdef SIGVTALRM
1929 sigaction (SIGVTALRM, &process_fatal_action, 0);
1930#endif
1931#ifdef SIGXCPU
1932 sigaction (SIGXCPU, &process_fatal_action, 0);
1933#endif
1934#ifdef SIGXFSZ
1935 sigaction (SIGXFSZ, &process_fatal_action, 0);
1936#endif
1937
1938#ifdef SIGDANGER
1939 /* This just means available memory is getting low. */
1940 emacs_sigaction_init (&action, deliver_danger_signal);
1941 sigaction (SIGDANGER, &action, 0);
1942#endif
1943
1944 /* AIX-specific signals. */
1945#ifdef SIGGRANT
1946 sigaction (SIGGRANT, &process_fatal_action, 0);
1947#endif
1948#ifdef SIGMIGRATE
1949 sigaction (SIGMIGRATE, &process_fatal_action, 0);
1950#endif
1951#ifdef SIGMSG
1952 sigaction (SIGMSG, &process_fatal_action, 0);
1953#endif
1954#ifdef SIGRETRACT
1955 sigaction (SIGRETRACT, &process_fatal_action, 0);
1956#endif
1957#ifdef SIGSAK
1958 sigaction (SIGSAK, &process_fatal_action, 0);
1959#endif
1960#ifdef SIGSOUND
1961 sigaction (SIGSOUND, &process_fatal_action, 0);
1962#endif
1963#ifdef SIGTALRM
1964 sigaction (SIGTALRM, &thread_fatal_action, 0);
1965#endif
ca9c0567
PE
1966}
1967\f
9927a7b1 1968#ifndef HAVE_RANDOM
4bb8c8b7
KH
1969#ifdef random
1970#define HAVE_RANDOM
1971#endif
1972#endif
1973
1974/* Figure out how many bits the system's random number generator uses.
1975 `random' and `lrand48' are assumed to return 31 usable bits.
1976 BSD `rand' returns a 31 bit value but the low order bits are unusable;
1977 so we'll shift it and treat it like the 15-bit USG `rand'. */
1978
1979#ifndef RAND_BITS
1980# ifdef HAVE_RANDOM
1981# define RAND_BITS 31
1982# else /* !HAVE_RANDOM */
1983# ifdef HAVE_LRAND48
1984# define RAND_BITS 31
1985# define random lrand48
1986# else /* !HAVE_LRAND48 */
1987# define RAND_BITS 15
1988# if RAND_MAX == 32767
1989# define random rand
1990# else /* RAND_MAX != 32767 */
1991# if RAND_MAX == 2147483647
1992# define random() (rand () >> 16)
1993# else /* RAND_MAX != 2147483647 */
1994# ifdef USG
1995# define random rand
1996# else
1997# define random() (rand () >> 16)
2a633456 1998# endif /* !USG */
4bb8c8b7
KH
1999# endif /* RAND_MAX != 2147483647 */
2000# endif /* RAND_MAX != 32767 */
2001# endif /* !HAVE_LRAND48 */
2002# endif /* !HAVE_RANDOM */
2003#endif /* !RAND_BITS */
2e46c7c6 2004
4bb8c8b7 2005void
0e23ef9d 2006seed_random (void *seed, ptrdiff_t seed_size)
86a5659e 2007{
33634217 2008#if defined HAVE_RANDOM || ! defined HAVE_LRAND48
0e23ef9d
PE
2009 unsigned int arg = 0;
2010#else
2011 long int arg = 0;
2012#endif
2013 unsigned char *argp = (unsigned char *) &arg;
2014 unsigned char *seedp = seed;
2015 ptrdiff_t i;
2016 for (i = 0; i < seed_size; i++)
2017 argp[i % sizeof arg] ^= seedp[i];
4bb8c8b7 2018#ifdef HAVE_RANDOM
0e23ef9d 2019 srandom (arg);
f8b53a82 2020#else
4bb8c8b7 2021# ifdef HAVE_LRAND48
76425a49 2022 srand48 (arg);
4bb8c8b7 2023# else
0e23ef9d 2024 srand (arg);
4bb8c8b7 2025# endif
2e46c7c6 2026#endif
86a5659e
JB
2027}
2028
0e23ef9d
PE
2029void
2030init_random (void)
2031{
2032 EMACS_TIME t = current_emacs_time ();
2033 uintmax_t v = getpid () ^ EMACS_SECS (t) ^ EMACS_NSECS (t);
2034 seed_random (&v, sizeof v);
2035}
2036
4bb8c8b7 2037/*
d8ed26bd
PE
2038 * Return a nonnegative random integer out of whatever we've got.
2039 * It contains enough bits to make a random (signed) Emacs fixnum.
4bb8c8b7
KH
2040 * This suffices even for a 64-bit architecture with a 15-bit rand.
2041 */
ede49d71 2042EMACS_INT
971de7fb 2043get_random (void)
4bb8c8b7 2044{
ede49d71
PE
2045 EMACS_UINT val = 0;
2046 int i;
d8ed26bd
PE
2047 for (i = 0; i < (FIXNUM_BITS + RAND_BITS - 1) / RAND_BITS; i++)
2048 val = (random () ^ (val << RAND_BITS)
2049 ^ (val >> (BITS_PER_EMACS_INT - RAND_BITS)));
2050 val ^= val >> (BITS_PER_EMACS_INT - FIXNUM_BITS);
2051 return val & INTMASK;
4bb8c8b7 2052}
7088d1ca 2053
55e5faa1
PE
2054#ifndef HAVE_SNPRINTF
2055/* Approximate snprintf as best we can on ancient hosts that lack it. */
2056int
2057snprintf (char *buf, size_t bufsize, char const *format, ...)
2058{
2059 ptrdiff_t size = min (bufsize, PTRDIFF_MAX);
2060 ptrdiff_t nbytes = size - 1;
2061 va_list ap;
2062
2063 if (size)
2064 {
2065 va_start (ap, format);
2066 nbytes = doprnt (buf, size, format, 0, ap);
2067 va_end (ap);
2068 }
2069
2070 if (nbytes == size - 1)
2071 {
2072 /* Calculate the length of the string that would have been created
2073 had the buffer been large enough. */
2074 char stackbuf[4000];
2075 char *b = stackbuf;
2076 ptrdiff_t bsize = sizeof stackbuf;
2077 va_start (ap, format);
2078 nbytes = evxprintf (&b, &bsize, stackbuf, -1, format, ap);
2079 va_end (ap);
2080 if (b != stackbuf)
2081 xfree (b);
2082 }
2083
2084 if (INT_MAX < nbytes)
2085 {
31bed486 2086#ifdef EOVERFLOW
55e5faa1 2087 errno = EOVERFLOW;
31bed486
EZ
2088#else
2089 errno = EDOM;
2090#endif
55e5faa1
PE
2091 return -1;
2092 }
2093 return nbytes;
2094}
2095#endif
86a5659e 2096\f
cf29dd84
PE
2097/* If a backtrace is available, output the top lines of it to stderr.
2098 Do not output more than BACKTRACE_LIMIT or BACKTRACE_LIMIT_MAX lines.
2099 This function may be called from a signal handler, so it should
2100 not invoke async-unsafe functions like malloc. */
2101void
2102emacs_backtrace (int backtrace_limit)
2103{
4d7e6e51 2104 void *main_backtrace_buffer[BACKTRACE_LIMIT_MAX + 1];
cf29dd84 2105 int bounded_limit = min (backtrace_limit, BACKTRACE_LIMIT_MAX);
4d7e6e51
PE
2106 void *buffer;
2107 int npointers;
2108
2109 if (thread_backtrace_npointers)
2110 {
2111 buffer = thread_backtrace_buffer;
2112 npointers = thread_backtrace_npointers;
2113 }
2114 else
2115 {
2116 buffer = main_backtrace_buffer;
2117 npointers = backtrace (buffer, bounded_limit + 1);
2118 }
2119
cf29dd84 2120 if (npointers)
4d7e6e51
PE
2121 {
2122 ignore_value (write (STDERR_FILENO, "\nBacktrace:\n", 12));
2123 backtrace_symbols_fd (buffer, npointers, STDERR_FILENO);
2124 if (bounded_limit < npointers)
2125 ignore_value (write (STDERR_FILENO, "...\n", 4));
2126 }
cf29dd84
PE
2127}
2128\f
1088b922 2129#ifndef HAVE_NTGUI
1088b922
PE
2130void
2131emacs_abort (void)
2132{
4d7e6e51 2133 terminate_due_to_signal (SIGABRT, 10);
1088b922
PE
2134}
2135#endif
2136
86a5659e 2137int
971de7fb 2138emacs_open (const char *path, int oflag, int mode)
86a5659e
JB
2139{
2140 register int rtnval;
68c45bf0 2141
86a5659e 2142 while ((rtnval = open (path, oflag, mode)) == -1
275464e7
SM
2143 && (errno == EINTR))
2144 QUIT;
86a5659e
JB
2145 return (rtnval);
2146}
2147
dfcf069d 2148int
971de7fb 2149emacs_close (int fd)
86a5659e 2150{
fe111daf 2151 int did_retry = 0;
86a5659e
JB
2152 register int rtnval;
2153
2154 while ((rtnval = close (fd)) == -1
fe111daf
KH
2155 && (errno == EINTR))
2156 did_retry = 1;
2157
2158 /* If close is interrupted SunOS 4.1 may or may not have closed the
2159 file descriptor. If it did the second close will fail with
2160 errno = EBADF. That means we have succeeded. */
2161 if (rtnval == -1 && did_retry && errno == EBADF)
2162 return 0;
2163
86a5659e
JB
2164 return rtnval;
2165}
2166
1963a2e0
PE
2167/* Maximum number of bytes to read or write in a single system call.
2168 This works around a serious bug in Linux kernels before 2.6.16; see
2169 <https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=612839>.
2170 It's likely to work around similar bugs in other operating systems, so do it
2171 on all platforms. Round INT_MAX down to a page size, with the conservative
2172 assumption that page sizes are at most 2**18 bytes (any kernel with a
2173 page size larger than that shouldn't have the bug). */
2174#ifndef MAX_RW_COUNT
2175#define MAX_RW_COUNT (INT_MAX >> 18 << 18)
2176#endif
2177
273a5f82
PE
2178/* Read from FILEDESC to a buffer BUF with size NBYTE, retrying if interrupted.
2179 Return the number of bytes read, which might be less than NBYTE.
2180 On error, set errno and return -1. */
d311d28c
PE
2181ptrdiff_t
2182emacs_read (int fildes, char *buf, ptrdiff_t nbyte)
86a5659e 2183{
8a2cbd72 2184 register ssize_t rtnval;
177c0ea7 2185
71b41406
PE
2186 /* There is no need to check against MAX_RW_COUNT, since no caller ever
2187 passes a size that large to emacs_read. */
2188
2189 while ((rtnval = read (fildes, buf, nbyte)) == -1
275464e7
SM
2190 && (errno == EINTR))
2191 QUIT;
86a5659e
JB
2192 return (rtnval);
2193}
2194
273a5f82
PE
2195/* Write to FILEDES from a buffer BUF with size NBYTE, retrying if interrupted
2196 or if a partial write occurs. Return the number of bytes written, setting
2197 errno if this is less than NBYTE. */
d311d28c
PE
2198ptrdiff_t
2199emacs_write (int fildes, const char *buf, ptrdiff_t nbyte)
86a5659e 2200{
273a5f82 2201 ssize_t rtnval;
d311d28c 2202 ptrdiff_t bytes_written;
28272684 2203
b95520f5
BF
2204 bytes_written = 0;
2205
273a5f82 2206 while (nbyte > 0)
b95520f5 2207 {
1963a2e0 2208 rtnval = write (fildes, buf, min (nbyte, MAX_RW_COUNT));
b95520f5 2209
273a5f82 2210 if (rtnval < 0)
b95520f5
BF
2211 {
2212 if (errno == EINTR)
77220eeb 2213 {
77220eeb
SM
2214 /* I originally used `QUIT' but that might causes files to
2215 be truncated if you hit C-g in the middle of it. --Stef */
4d7e6e51
PE
2216 if (pending_signals)
2217 process_pending_signals ();
77220eeb
SM
2218 continue;
2219 }
b95520f5 2220 else
273a5f82 2221 break;
b95520f5
BF
2222 }
2223
2224 buf += rtnval;
2225 nbyte -= rtnval;
2226 bytes_written += rtnval;
2227 }
273a5f82 2228
b95520f5 2229 return (bytes_written);
86a5659e 2230}
d1fdcab7
PE
2231
2232static struct allocator const emacs_norealloc_allocator =
2233 { xmalloc, NULL, xfree, memory_full };
2234
2235/* Get the symbolic link value of FILENAME. Return a pointer to a
2236 NUL-terminated string. If readlink fails, return NULL and set
2237 errno. If the value fits in INITIAL_BUF, return INITIAL_BUF.
2238 Otherwise, allocate memory and return a pointer to that memory. If
2239 memory allocation fails, diagnose and fail without returning. If
2240 successful, store the length of the symbolic link into *LINKLEN. */
2241char *
2242emacs_readlink (char const *filename, char initial_buf[READLINK_BUFSIZE])
2243{
2244 return careadlinkat (AT_FDCWD, filename, initial_buf, READLINK_BUFSIZE,
2245 &emacs_norealloc_allocator, careadlinkatcwd);
2246}
86a5659e
JB
2247\f
2248#ifdef USG
2249/*
2250 * All of the following are for USG.
2251 *
2252 * On USG systems the system calls are INTERRUPTIBLE by signals
2253 * that the user program has elected to catch. Thus the system call
2254 * must be retried in these cases. To handle this without massive
2255 * changes in the source code, we remap the standard system call names
2256 * to names for our own functions in sysdep.c that do the system call
2257 * with retries. Actually, for portability reasons, it is good
2258 * programming practice, as this example shows, to limit all actual
eb8c3be9 2259 * system calls to a single occurrence in the source. Sure, this
86a5659e
JB
2260 * adds an extra level of function call overhead but it is almost
2261 * always negligible. Fred Fish, Unisoft Systems Inc.
2262 */
2263
86a5659e
JB
2264/*
2265 * Warning, this function may not duplicate 4.2 action properly
2266 * under error conditions.
2267 */
2268
1db4583a 2269#if !defined (HAVE_GETWD) || defined (BROKEN_GETWD)
15dfd3d9 2270
86a5659e
JB
2271#ifndef MAXPATHLEN
2272/* In 4.1, param.h fails to define this. */
2273#define MAXPATHLEN 1024
2274#endif
2275
86a5659e 2276char *
cf84bb53 2277getwd (char *pathname)
86a5659e
JB
2278{
2279 char *npath, *spath;
cf84bb53 2280 extern char *getcwd (char *, size_t);
86a5659e 2281
4d7e6e51 2282 block_input (); /* getcwd uses malloc */
86a5659e 2283 spath = npath = getcwd ((char *) 0, MAXPATHLEN);
f4a7e5bd 2284 if (spath == 0)
18b6bc73 2285 {
4d7e6e51 2286 unblock_input ();
18b6bc73
GM
2287 return spath;
2288 }
86a5659e
JB
2289 /* On Altos 3068, getcwd can return @hostname/dir, so discard
2290 up to first slash. Should be harmless on other systems. */
2291 while (*npath && *npath != '/')
2292 npath++;
2293 strcpy (pathname, npath);
2294 free (spath); /* getcwd uses malloc */
4d7e6e51 2295 unblock_input ();
86a5659e
JB
2296 return pathname;
2297}
2298
1db4583a 2299#endif /* !defined (HAVE_GETWD) || defined (BROKEN_GETWD) */
86a5659e
JB
2300#endif /* USG */
2301\f
86a5659e
JB
2302/* Directory routines for systems that don't have them. */
2303
1c97e857 2304#ifdef HAVE_DIRENT_H
86a5659e
JB
2305
2306#include <dirent.h>
2307
9d9a7716 2308#if !defined (HAVE_CLOSEDIR)
cfdc57af 2309
86a5659e 2310int
9d9a7716 2311closedir (DIR *dirp /* stream from opendir */)
86a5659e 2312{
cfdc57af
RS
2313 int rtnval;
2314
68c45bf0 2315 rtnval = emacs_close (dirp->dd_fd);
98c6f1e3 2316 xfree (dirp);
cfdc57af
RS
2317
2318 return rtnval;
86a5659e 2319}
9d9a7716 2320#endif /* not HAVE_CLOSEDIR */
1c97e857 2321#endif /* HAVE_DIRENT_H */
86a5659e 2322
23524fb9 2323\f
d35af63c
PE
2324/* Return a struct timeval that is roughly equivalent to T.
2325 Use the least timeval not less than T.
2326 Return an extremal value if the result would overflow. */
2327struct timeval
2328make_timeval (EMACS_TIME t)
2329{
2330 struct timeval tv;
2331 tv.tv_sec = t.tv_sec;
2332 tv.tv_usec = t.tv_nsec / 1000;
2333
2334 if (t.tv_nsec % 1000 != 0)
2335 {
2336 if (tv.tv_usec < 999999)
2337 tv.tv_usec++;
2338 else if (tv.tv_sec < TYPE_MAXIMUM (time_t))
2339 {
2340 tv.tv_sec++;
2341 tv.tv_usec = 0;
2342 }
2343 }
2344
2345 return tv;
2346}
2347
2348/* Set the access and modification time stamps of FD (a.k.a. FILE) to be
2349 ATIME and MTIME, respectively.
2350 FD must be either negative -- in which case it is ignored --
2351 or a file descriptor that is open on FILE.
2352 If FD is nonnegative, then FILE can be NULL. */
53ea491a 2353int
d35af63c
PE
2354set_file_times (int fd, const char *filename,
2355 EMACS_TIME atime, EMACS_TIME mtime)
2356{
2357 struct timespec timespec[2];
2358 timespec[0] = atime;
2359 timespec[1] = mtime;
2360 return fdutimens (fd, filename, timespec);
53ea491a
KH
2361}
2362\f
aa1ba90e
PE
2363/* Like strsignal, except async-signal-safe, and this function typically
2364 returns a string in the C locale rather than the current locale. */
2365char const *
2366safe_strsignal (int code)
68c45bf0 2367{
aa1ba90e 2368 char const *signame = 0;
68c45bf0 2369
c622b48f 2370 if (0 <= code && code < sys_siglist_entries)
aa1ba90e
PE
2371 signame = sys_siglist[code];
2372 if (! signame)
2373 signame = "Unknown signal";
c4ea52a6 2374
68c45bf0
PE
2375 return signame;
2376}
d888760c 2377\f
a7ebc409 2378#ifndef DOS_NT
d888760c 2379/* For make-serial-process */
cf84bb53
JB
2380int
2381serial_open (char *port)
d888760c
GM
2382{
2383 int fd = -1;
2384
2385 fd = emacs_open ((char*) port,
2386 O_RDWR
2387#ifdef O_NONBLOCK
2388 | O_NONBLOCK
2389#else
2390 | O_NDELAY
2391#endif
2392#ifdef O_NOCTTY
2393 | O_NOCTTY
2394#endif
2395 , 0);
2396 if (fd < 0)
2397 {
2398 error ("Could not open %s: %s",
2399 port, emacs_strerror (errno));
2400 }
2401#ifdef TIOCEXCL
2402 ioctl (fd, TIOCEXCL, (char *) 0);
2403#endif
2404
2405 return fd;
2406}
759d3f32
SM
2407
2408#if !defined (HAVE_CFMAKERAW)
2409/* Workaround for targets which are missing cfmakeraw. */
2410/* Pasted from man page. */
cf84bb53
JB
2411static void
2412cfmakeraw (struct termios *termios_p)
759d3f32
SM
2413{
2414 termios_p->c_iflag &= ~(IGNBRK|BRKINT|PARMRK|ISTRIP|INLCR|IGNCR|ICRNL|IXON);
2415 termios_p->c_oflag &= ~OPOST;
2416 termios_p->c_lflag &= ~(ECHO|ECHONL|ICANON|ISIG|IEXTEN);
2417 termios_p->c_cflag &= ~(CSIZE|PARENB);
2418 termios_p->c_cflag |= CS8;
2419}
2420#endif /* !defined (HAVE_CFMAKERAW */
2421
2422#if !defined (HAVE_CFSETSPEED)
2423/* Workaround for targets which are missing cfsetspeed. */
cf84bb53
JB
2424static int
2425cfsetspeed (struct termios *termios_p, speed_t vitesse)
759d3f32
SM
2426{
2427 return (cfsetispeed (termios_p, vitesse)
2428 + cfsetospeed (termios_p, vitesse));
2429}
2430#endif
2431
d888760c
GM
2432/* For serial-process-configure */
2433void
2434serial_configure (struct Lisp_Process *p,
cf84bb53 2435 Lisp_Object contact)
d888760c
GM
2436{
2437 Lisp_Object childp2 = Qnil;
2438 Lisp_Object tem = Qnil;
2439 struct termios attr;
2440 int err = -1;
2441 char summary[4] = "???"; /* This usually becomes "8N1". */
2442
4d2b044c 2443 childp2 = Fcopy_sequence (p->childp);
d888760c
GM
2444
2445 /* Read port attributes and prepare default configuration. */
2446 err = tcgetattr (p->outfd, &attr);
2447 if (err != 0)
2448 error ("tcgetattr() failed: %s", emacs_strerror (errno));
2449 cfmakeraw (&attr);
2450#if defined (CLOCAL)
2451 attr.c_cflag |= CLOCAL;
2452#endif
2453#if defined (CREAD)
6d1921be 2454 attr.c_cflag |= CREAD;
d888760c
GM
2455#endif
2456
2457 /* Configure speed. */
2458 if (!NILP (Fplist_member (contact, QCspeed)))
2459 tem = Fplist_get (contact, QCspeed);
2460 else
4d2b044c 2461 tem = Fplist_get (p->childp, QCspeed);
d888760c
GM
2462 CHECK_NUMBER (tem);
2463 err = cfsetspeed (&attr, XINT (tem));
2464 if (err != 0)
c2982e87 2465 error ("cfsetspeed(%"pI"d) failed: %s", XINT (tem),
5fdb398c 2466 emacs_strerror (errno));
d888760c
GM
2467 childp2 = Fplist_put (childp2, QCspeed, tem);
2468
2469 /* Configure bytesize. */
2470 if (!NILP (Fplist_member (contact, QCbytesize)))
2471 tem = Fplist_get (contact, QCbytesize);
2472 else
4d2b044c 2473 tem = Fplist_get (p->childp, QCbytesize);
d888760c
GM
2474 if (NILP (tem))
2475 tem = make_number (8);
2476 CHECK_NUMBER (tem);
2477 if (XINT (tem) != 7 && XINT (tem) != 8)
2478 error (":bytesize must be nil (8), 7, or 8");
cf84bb53 2479 summary[0] = XINT (tem) + '0';
d888760c
GM
2480#if defined (CSIZE) && defined (CS7) && defined (CS8)
2481 attr.c_cflag &= ~CSIZE;
2482 attr.c_cflag |= ((XINT (tem) == 7) ? CS7 : CS8);
2483#else
16bad4dd 2484 /* Don't error on bytesize 8, which should be set by cfmakeraw. */
d888760c
GM
2485 if (XINT (tem) != 8)
2486 error ("Bytesize cannot be changed");
2487#endif
2488 childp2 = Fplist_put (childp2, QCbytesize, tem);
2489
2490 /* Configure parity. */
2491 if (!NILP (Fplist_member (contact, QCparity)))
2492 tem = Fplist_get (contact, QCparity);
2493 else
4d2b044c 2494 tem = Fplist_get (p->childp, QCparity);
d888760c
GM
2495 if (!NILP (tem) && !EQ (tem, Qeven) && !EQ (tem, Qodd))
2496 error (":parity must be nil (no parity), `even', or `odd'");
2497#if defined (PARENB) && defined (PARODD) && defined (IGNPAR) && defined (INPCK)
2498 attr.c_cflag &= ~(PARENB | PARODD);
2499 attr.c_iflag &= ~(IGNPAR | INPCK);
2500 if (NILP (tem))
2501 {
2502 summary[1] = 'N';
2503 }
2504 else if (EQ (tem, Qeven))
2505 {
2506 summary[1] = 'E';
2507 attr.c_cflag |= PARENB;
2508 attr.c_iflag |= (IGNPAR | INPCK);
2509 }
2510 else if (EQ (tem, Qodd))
2511 {
2512 summary[1] = 'O';
2513 attr.c_cflag |= (PARENB | PARODD);
2514 attr.c_iflag |= (IGNPAR | INPCK);
2515 }
2516#else
16bad4dd 2517 /* Don't error on no parity, which should be set by cfmakeraw. */
d888760c
GM
2518 if (!NILP (tem))
2519 error ("Parity cannot be configured");
2520#endif
2521 childp2 = Fplist_put (childp2, QCparity, tem);
2522
2523 /* Configure stopbits. */
2524 if (!NILP (Fplist_member (contact, QCstopbits)))
2525 tem = Fplist_get (contact, QCstopbits);
2526 else
4d2b044c 2527 tem = Fplist_get (p->childp, QCstopbits);
d888760c
GM
2528 if (NILP (tem))
2529 tem = make_number (1);
2530 CHECK_NUMBER (tem);
2531 if (XINT (tem) != 1 && XINT (tem) != 2)
2532 error (":stopbits must be nil (1 stopbit), 1, or 2");
2533 summary[2] = XINT (tem) + '0';
2534#if defined (CSTOPB)
2535 attr.c_cflag &= ~CSTOPB;
2536 if (XINT (tem) == 2)
2537 attr.c_cflag |= CSTOPB;
2538#else
16bad4dd 2539 /* Don't error on 1 stopbit, which should be set by cfmakeraw. */
d888760c
GM
2540 if (XINT (tem) != 1)
2541 error ("Stopbits cannot be configured");
2542#endif
2543 childp2 = Fplist_put (childp2, QCstopbits, tem);
2544
2545 /* Configure flowcontrol. */
2546 if (!NILP (Fplist_member (contact, QCflowcontrol)))
2547 tem = Fplist_get (contact, QCflowcontrol);
2548 else
4d2b044c 2549 tem = Fplist_get (p->childp, QCflowcontrol);
d888760c
GM
2550 if (!NILP (tem) && !EQ (tem, Qhw) && !EQ (tem, Qsw))
2551 error (":flowcontrol must be nil (no flowcontrol), `hw', or `sw'");
2552#if defined (CRTSCTS)
2553 attr.c_cflag &= ~CRTSCTS;
2554#endif
2555#if defined (CNEW_RTSCTS)
2556 attr.c_cflag &= ~CNEW_RTSCTS;
2557#endif
2558#if defined (IXON) && defined (IXOFF)
2559 attr.c_iflag &= ~(IXON | IXOFF);
2560#endif
2561 if (NILP (tem))
2562 {
2563 /* Already configured. */
2564 }
2565 else if (EQ (tem, Qhw))
2566 {
2567#if defined (CRTSCTS)
2568 attr.c_cflag |= CRTSCTS;
2569#elif defined (CNEW_RTSCTS)
2570 attr.c_cflag |= CNEW_RTSCTS;
2571#else
2572 error ("Hardware flowcontrol (RTS/CTS) not supported");
2573#endif
2574 }
2575 else if (EQ (tem, Qsw))
2576 {
2577#if defined (IXON) && defined (IXOFF)
2578 attr.c_iflag |= (IXON | IXOFF);
2579#else
2580 error ("Software flowcontrol (XON/XOFF) not supported");
2581#endif
2582 }
2583 childp2 = Fplist_put (childp2, QCflowcontrol, tem);
2584
2585 /* Activate configuration. */
2586 err = tcsetattr (p->outfd, TCSANOW, &attr);
2587 if (err != 0)
2588 error ("tcsetattr() failed: %s", emacs_strerror (errno));
2589
2590 childp2 = Fplist_put (childp2, QCsummary, build_string (summary));
6a09a33b 2591 pset_childp (p, childp2);
d888760c 2592}
a7ebc409 2593#endif /* not DOS_NT */
06e111a6
DN
2594\f
2595/* System depended enumeration of and access to system processes a-la ps(1). */
2596
2597#ifdef HAVE_PROCFS
2598
2599/* Process enumeration and access via /proc. */
2600
2601Lisp_Object
971de7fb 2602list_system_processes (void)
06e111a6
DN
2603{
2604 Lisp_Object procdir, match, proclist, next;
2605 struct gcpro gcpro1, gcpro2;
2606 register Lisp_Object tail;
2607
2608 GCPRO2 (procdir, match);
2609 /* For every process on the system, there's a directory in the
2610 "/proc" pseudo-directory whose name is the numeric ID of that
2611 process. */
2612 procdir = build_string ("/proc");
2613 match = build_string ("[0-9]+");
86ec63ba 2614 proclist = directory_files_internal (procdir, Qnil, match, Qt, 0, Qnil);
06e111a6
DN
2615
2616 /* `proclist' gives process IDs as strings. Destructively convert
2617 each string into a number. */
2618 for (tail = proclist; CONSP (tail); tail = next)
2619 {
2620 next = XCDR (tail);
2621 XSETCAR (tail, Fstring_to_number (XCAR (tail), Qnil));
2622 }
2623 UNGCPRO;
2624
2625 /* directory_files_internal returns the files in reverse order; undo
2626 that. */
2627 proclist = Fnreverse (proclist);
2628 return proclist;
2629}
2630
f01769f9 2631#elif defined BSD_SYSTEM
b91b7e4d
EW
2632
2633Lisp_Object
5790543d 2634list_system_processes (void)
b91b7e4d 2635{
f3047c75 2636#if defined DARWIN_OS || defined __NetBSD__ || defined __OpenBSD__
f01769f9
LL
2637 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_ALL};
2638#else
b91b7e4d 2639 int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PROC};
f01769f9 2640#endif
b91b7e4d
EW
2641 size_t len;
2642 struct kinfo_proc *procs;
2643 size_t i;
2644
2645 struct gcpro gcpro1;
2646 Lisp_Object proclist = Qnil;
2647
2648 if (sysctl (mib, 3, NULL, &len, NULL, 0) != 0)
2649 return proclist;
5790543d 2650
b91b7e4d
EW
2651 procs = xmalloc (len);
2652 if (sysctl (mib, 3, procs, &len, NULL, 0) != 0)
2653 {
2654 xfree (procs);
2655 return proclist;
2656 }
5790543d 2657
b91b7e4d
EW
2658 GCPRO1 (proclist);
2659 len /= sizeof (struct kinfo_proc);
2660 for (i = 0; i < len; i++)
f01769f9 2661 {
f3047c75 2662#if defined DARWIN_OS || defined __NetBSD__
f01769f9 2663 proclist = Fcons (make_fixnum_or_float (procs[i].kp_proc.p_pid), proclist);
7dca65a4
PE
2664#elif defined __OpenBSD__
2665 proclist = Fcons (make_fixnum_or_float (procs[i].p_pid), proclist);
f01769f9
LL
2666#else
2667 proclist = Fcons (make_fixnum_or_float (procs[i].ki_pid), proclist);
2668#endif
2669 }
b91b7e4d 2670 UNGCPRO;
5790543d 2671
b91b7e4d
EW
2672 xfree (procs);
2673
2674 return proclist;
2675}
2676
f8d23104
DN
2677/* The WINDOWSNT implementation is in w32.c.
2678 The MSDOS implementation is in dosfns.c. */
c4605e09 2679#elif !defined (WINDOWSNT) && !defined (MSDOS)
06e111a6
DN
2680
2681Lisp_Object
cf84bb53 2682list_system_processes (void)
06e111a6
DN
2683{
2684 return Qnil;
2685}
91c85b70
EZ
2686
2687#endif /* !defined (WINDOWSNT) */
06e111a6
DN
2688
2689#ifdef GNU_LINUX
d35af63c
PE
2690static EMACS_TIME
2691time_from_jiffies (unsigned long long tval, long hz)
2692{
2693 unsigned long long s = tval / hz;
2694 unsigned long long frac = tval % hz;
2695 int ns;
d35af63c
PE
2696
2697 if (TYPE_MAXIMUM (time_t) < s)
2698 time_overflow ();
2699 if (LONG_MAX - 1 <= ULLONG_MAX / EMACS_TIME_RESOLUTION
2700 || frac <= ULLONG_MAX / EMACS_TIME_RESOLUTION)
2701 ns = frac * EMACS_TIME_RESOLUTION / hz;
06e111a6 2702 else
d35af63c
PE
2703 {
2704 /* This is reachable only in the unlikely case that HZ * HZ
2705 exceeds ULLONG_MAX. It calculates an approximation that is
2706 guaranteed to be in range. */
2707 long hz_per_ns = (hz / EMACS_TIME_RESOLUTION
2708 + (hz % EMACS_TIME_RESOLUTION != 0));
2709 ns = frac / hz_per_ns;
2710 }
2711
e9a9ae03 2712 return make_emacs_time (s, ns);
06e111a6
DN
2713}
2714
2715static Lisp_Object
2716ltime_from_jiffies (unsigned long long tval, long hz)
2717{
d35af63c
PE
2718 EMACS_TIME t = time_from_jiffies (tval, hz);
2719 return make_lisp_time (t);
06e111a6
DN
2720}
2721
d35af63c
PE
2722static EMACS_TIME
2723get_up_time (void)
06e111a6
DN
2724{
2725 FILE *fup;
e9a9ae03 2726 EMACS_TIME up = make_emacs_time (0, 0);
06e111a6 2727
4d7e6e51 2728 block_input ();
06e111a6
DN
2729 fup = fopen ("/proc/uptime", "r");
2730
2731 if (fup)
2732 {
d35af63c
PE
2733 unsigned long long upsec, upfrac, idlesec, idlefrac;
2734 int upfrac_start, upfrac_end, idlefrac_start, idlefrac_end;
06e111a6 2735
d35af63c
PE
2736 if (fscanf (fup, "%llu.%n%llu%n %llu.%n%llu%n",
2737 &upsec, &upfrac_start, &upfrac, &upfrac_end,
2738 &idlesec, &idlefrac_start, &idlefrac, &idlefrac_end)
2739 == 4)
06e111a6 2740 {
d35af63c
PE
2741 if (TYPE_MAXIMUM (time_t) < upsec)
2742 {
2743 upsec = TYPE_MAXIMUM (time_t);
2744 upfrac = EMACS_TIME_RESOLUTION - 1;
2745 }
2746 else
2747 {
2748 int upfraclen = upfrac_end - upfrac_start;
2749 for (; upfraclen < LOG10_EMACS_TIME_RESOLUTION; upfraclen++)
2750 upfrac *= 10;
2751 for (; LOG10_EMACS_TIME_RESOLUTION < upfraclen; upfraclen--)
2752 upfrac /= 10;
2753 upfrac = min (upfrac, EMACS_TIME_RESOLUTION - 1);
2754 }
e9a9ae03 2755 up = make_emacs_time (upsec, upfrac);
06e111a6
DN
2756 }
2757 fclose (fup);
2758 }
4d7e6e51 2759 unblock_input ();
d35af63c
PE
2760
2761 return up;
06e111a6
DN
2762}
2763
2764#define MAJOR(d) (((unsigned)(d) >> 8) & 0xfff)
2765#define MINOR(d) (((unsigned)(d) & 0xff) | (((unsigned)(d) & 0xfff00000) >> 12))
2766
2767static Lisp_Object
f4f634e8 2768procfs_ttyname (int rdev)
06e111a6
DN
2769{
2770 FILE *fdev = NULL;
2771 char name[PATH_MAX];
2772
4d7e6e51 2773 block_input ();
06e111a6
DN
2774 fdev = fopen ("/proc/tty/drivers", "r");
2775
2776 if (fdev)
2777 {
2778 unsigned major;
2779 unsigned long minor_beg, minor_end;
2780 char minor[25]; /* 2 32-bit numbers + dash */
2781 char *endp;
2782
2783 while (!feof (fdev) && !ferror (fdev))
2784 {
2785 if (3 <= fscanf (fdev, "%*s %s %u %s %*s\n", name, &major, minor)
2786 && major == MAJOR (rdev))
2787 {
2788 minor_beg = strtoul (minor, &endp, 0);
2789 if (*endp == '\0')
2790 minor_end = minor_beg;
2791 else if (*endp == '-')
2792 minor_end = strtoul (endp + 1, &endp, 0);
2793 else
2794 continue;
2795
2796 if (MINOR (rdev) >= minor_beg && MINOR (rdev) <= minor_end)
2797 {
10d66ec0 2798 sprintf (name + strlen (name), "%u", MINOR (rdev));
06e111a6
DN
2799 break;
2800 }
2801 }
2802 }
2803 fclose (fdev);
2804 }
4d7e6e51 2805 unblock_input ();
06e111a6
DN
2806 return build_string (name);
2807}
2808
2809static unsigned long
2810procfs_get_total_memory (void)
2811{
2812 FILE *fmem = NULL;
2813 unsigned long retval = 2 * 1024 * 1024; /* default: 2GB */
2814
4d7e6e51 2815 block_input ();
06e111a6
DN
2816 fmem = fopen ("/proc/meminfo", "r");
2817
2818 if (fmem)
2819 {
2820 unsigned long entry_value;
2821 char entry_name[20]; /* the longest I saw is 13+1 */
2822
2823 while (!feof (fmem) && !ferror (fmem))
2824 {
2825 if (2 <= fscanf (fmem, "%s %lu kB\n", entry_name, &entry_value)
2826 && strcmp (entry_name, "MemTotal:") == 0)
2827 {
2828 retval = entry_value;
2829 break;
2830 }
2831 }
2832 fclose (fmem);
2833 }
4d7e6e51 2834 unblock_input ();
06e111a6
DN
2835 return retval;
2836}
2837
2838Lisp_Object
f4f634e8 2839system_process_attributes (Lisp_Object pid)
06e111a6
DN
2840{
2841 char procfn[PATH_MAX], fn[PATH_MAX];
2842 struct stat st;
2843 struct passwd *pw;
2844 struct group *gr;
2845 long clocks_per_sec;
2846 char *procfn_end;
2847 char procbuf[1025], *p, *q;
2848 int fd;
2849 ssize_t nread;
e99a530f
PE
2850 static char const default_cmd[] = "???";
2851 const char *cmd = default_cmd;
2852 int cmdsize = sizeof default_cmd - 1;
06e111a6 2853 char *cmdline = NULL;
e99a530f 2854 ptrdiff_t cmdline_size;
06e111a6 2855 unsigned char c;
d311d28c
PE
2856 printmax_t proc_id;
2857 int ppid, pgrp, sess, tty, tpgid, thcount;
2858 uid_t uid;
2859 gid_t gid;
a70072c9
PE
2860 unsigned long long u_time, s_time, cutime, cstime, start;
2861 long priority, niceness, rss;
06e111a6 2862 unsigned long minflt, majflt, cminflt, cmajflt, vsize;
d35af63c 2863 EMACS_TIME tnow, tstart, tboot, telapsed, us_time;
06e111a6
DN
2864 double pcpu, pmem;
2865 Lisp_Object attrs = Qnil;
2866 Lisp_Object cmd_str, decoded_cmd, tem;
2867 struct gcpro gcpro1, gcpro2;
06e111a6
DN
2868
2869 CHECK_NUMBER_OR_FLOAT (pid);
225a2cff 2870 CONS_TO_INTEGER (pid, pid_t, proc_id);
d311d28c 2871 sprintf (procfn, "/proc/%"pMd, proc_id);
06e111a6
DN
2872 if (stat (procfn, &st) < 0)
2873 return attrs;
2874
2875 GCPRO2 (attrs, decoded_cmd);
2876
2877 /* euid egid */
2878 uid = st.st_uid;
d311d28c 2879 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs);
4d7e6e51 2880 block_input ();
06e111a6 2881 pw = getpwuid (uid);
4d7e6e51 2882 unblock_input ();
06e111a6
DN
2883 if (pw)
2884 attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
2885
2886 gid = st.st_gid;
d311d28c 2887 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid)), attrs);
4d7e6e51 2888 block_input ();
06e111a6 2889 gr = getgrgid (gid);
4d7e6e51 2890 unblock_input ();
06e111a6
DN
2891 if (gr)
2892 attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
2893
2894 strcpy (fn, procfn);
2895 procfn_end = fn + strlen (fn);
2896 strcpy (procfn_end, "/stat");
2897 fd = emacs_open (fn, O_RDONLY, 0);
cf84bb53 2898 if (fd >= 0 && (nread = emacs_read (fd, procbuf, sizeof (procbuf) - 1)) > 0)
06e111a6
DN
2899 {
2900 procbuf[nread] = '\0';
2901 p = procbuf;
2902
2903 p = strchr (p, '(');
2904 if (p != NULL)
2905 {
2906 q = strrchr (p + 1, ')');
2907 /* comm */
2908 if (q != NULL)
2909 {
2910 cmd = p + 1;
2911 cmdsize = q - cmd;
2912 }
2913 }
2914 else
2915 q = NULL;
06e111a6
DN
2916 /* Command name is encoded in locale-coding-system; decode it. */
2917 cmd_str = make_unibyte_string (cmd, cmdsize);
2918 decoded_cmd = code_convert_string_norecord (cmd_str,
2919 Vlocale_coding_system, 0);
2920 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
2921
2922 if (q)
2923 {
2924 EMACS_INT ppid_eint, pgrp_eint, sess_eint, tpgid_eint, thcount_eint;
2925 p = q + 2;
2926 /* state ppid pgrp sess tty tpgid . minflt cminflt majflt cmajflt utime stime cutime cstime priority nice thcount . start vsize rss */
2927 sscanf (p, "%c %d %d %d %d %d %*u %lu %lu %lu %lu %Lu %Lu %Lu %Lu %ld %ld %d %*d %Lu %lu %ld",
2928 &c, &ppid, &pgrp, &sess, &tty, &tpgid,
2929 &minflt, &cminflt, &majflt, &cmajflt,
a70072c9
PE
2930 &u_time, &s_time, &cutime, &cstime,
2931 &priority, &niceness, &thcount, &start, &vsize, &rss);
06e111a6
DN
2932 {
2933 char state_str[2];
2934
2935 state_str[0] = c;
2936 state_str[1] = '\0';
2937 tem = build_string (state_str);
2938 attrs = Fcons (Fcons (Qstate, tem), attrs);
2939 }
2940 /* Stops GCC whining about limited range of data type. */
2941 ppid_eint = ppid;
2942 pgrp_eint = pgrp;
2943 sess_eint = sess;
2944 tpgid_eint = tpgid;
2945 thcount_eint = thcount;
2946 attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (ppid_eint)), attrs);
2947 attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pgrp_eint)), attrs);
2948 attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (sess_eint)), attrs);
2949 attrs = Fcons (Fcons (Qttname, procfs_ttyname (tty)), attrs);
2950 attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (tpgid_eint)), attrs);
2951 attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (minflt)), attrs);
2952 attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (majflt)), attrs);
2953 attrs = Fcons (Fcons (Qcminflt, make_fixnum_or_float (cminflt)), attrs);
2954 attrs = Fcons (Fcons (Qcmajflt, make_fixnum_or_float (cmajflt)), attrs);
2955 clocks_per_sec = sysconf (_SC_CLK_TCK);
2956 if (clocks_per_sec < 0)
2957 clocks_per_sec = 100;
2958 attrs = Fcons (Fcons (Qutime,
a70072c9 2959 ltime_from_jiffies (u_time, clocks_per_sec)),
06e111a6
DN
2960 attrs);
2961 attrs = Fcons (Fcons (Qstime,
a70072c9 2962 ltime_from_jiffies (s_time, clocks_per_sec)),
06e111a6 2963 attrs);
ac1e4171 2964 attrs = Fcons (Fcons (Qtime,
a70072c9
PE
2965 ltime_from_jiffies (s_time + u_time,
2966 clocks_per_sec)),
ac1e4171 2967 attrs);
06e111a6
DN
2968 attrs = Fcons (Fcons (Qcutime,
2969 ltime_from_jiffies (cutime, clocks_per_sec)),
2970 attrs);
2971 attrs = Fcons (Fcons (Qcstime,
2972 ltime_from_jiffies (cstime, clocks_per_sec)),
ac1e4171
EZ
2973 attrs);
2974 attrs = Fcons (Fcons (Qctime,
2975 ltime_from_jiffies (cstime+cutime, clocks_per_sec)),
06e111a6
DN
2976 attrs);
2977 attrs = Fcons (Fcons (Qpri, make_number (priority)), attrs);
a70072c9 2978 attrs = Fcons (Fcons (Qnice, make_number (niceness)), attrs);
06e111a6 2979 attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (thcount_eint)), attrs);
e9a9ae03 2980 tnow = current_emacs_time ();
d35af63c 2981 telapsed = get_up_time ();
e9a9ae03 2982 tboot = sub_emacs_time (tnow, telapsed);
d35af63c 2983 tstart = time_from_jiffies (start, clocks_per_sec);
e9a9ae03 2984 tstart = add_emacs_time (tboot, tstart);
d35af63c 2985 attrs = Fcons (Fcons (Qstart, make_lisp_time (tstart)), attrs);
06e111a6
DN
2986 attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (vsize/1024)), attrs);
2987 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (4*rss)), attrs);
e9a9ae03 2988 telapsed = sub_emacs_time (tnow, tstart);
d35af63c
PE
2989 attrs = Fcons (Fcons (Qetime, make_lisp_time (telapsed)), attrs);
2990 us_time = time_from_jiffies (u_time + s_time, clocks_per_sec);
2991 pcpu = (EMACS_TIME_TO_DOUBLE (us_time)
2992 / EMACS_TIME_TO_DOUBLE (telapsed));
06e111a6
DN
2993 if (pcpu > 1.0)
2994 pcpu = 1.0;
2995 attrs = Fcons (Fcons (Qpcpu, make_float (100 * pcpu)), attrs);
2996 pmem = 4.0 * 100 * rss / procfs_get_total_memory ();
2997 if (pmem > 100)
2998 pmem = 100;
2999 attrs = Fcons (Fcons (Qpmem, make_float (pmem)), attrs);
3000 }
3001 }
3002 if (fd >= 0)
3003 emacs_close (fd);
3004
3005 /* args */
3006 strcpy (procfn_end, "/cmdline");
3007 fd = emacs_open (fn, O_RDONLY, 0);
3008 if (fd >= 0)
3009 {
fbd02d7b 3010 char ch;
fe6442b1 3011 for (cmdline_size = 0; cmdline_size < STRING_BYTES_BOUND; cmdline_size++)
06e111a6 3012 {
fe6442b1
PE
3013 if (emacs_read (fd, &ch, 1) != 1)
3014 break;
fbd02d7b 3015 c = ch;
620f13b0 3016 if (c_isspace (c) || c == '\\')
06e111a6
DN
3017 cmdline_size++; /* for later quoting, see below */
3018 }
3019 if (cmdline_size)
3020 {
3021 cmdline = xmalloc (cmdline_size + 1);
3022 lseek (fd, 0L, SEEK_SET);
3023 cmdline[0] = '\0';
3024 if ((nread = read (fd, cmdline, cmdline_size)) >= 0)
3025 cmdline[nread++] = '\0';
3026 else
3027 {
3028 /* Assigning zero to `nread' makes us skip the following
3029 two loops, assign zero to cmdline_size, and enter the
3030 following `if' clause that handles unknown command
3031 lines. */
3032 nread = 0;
3033 }
3034 /* We don't want trailing null characters. */
fe6442b1 3035 for (p = cmdline + nread; p > cmdline + 1 && !p[-1]; p--)
06e111a6
DN
3036 nread--;
3037 for (p = cmdline; p < cmdline + nread; p++)
3038 {
3039 /* Escape-quote whitespace and backslashes. */
620f13b0 3040 if (c_isspace (*p) || *p == '\\')
06e111a6
DN
3041 {
3042 memmove (p + 1, p, nread - (p - cmdline));
3043 nread++;
3044 *p++ = '\\';
3045 }
3046 else if (*p == '\0')
3047 *p = ' ';
3048 }
3049 cmdline_size = nread;
3050 }
3051 if (!cmdline_size)
3052 {
06e111a6
DN
3053 cmdline_size = cmdsize + 2;
3054 cmdline = xmalloc (cmdline_size + 1);
e99a530f 3055 sprintf (cmdline, "[%.*s]", cmdsize, cmd);
06e111a6
DN
3056 }
3057 emacs_close (fd);
3058 /* Command line is encoded in locale-coding-system; decode it. */
3059 cmd_str = make_unibyte_string (cmdline, cmdline_size);
3060 decoded_cmd = code_convert_string_norecord (cmd_str,
3061 Vlocale_coding_system, 0);
3062 xfree (cmdline);
3063 attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
3064 }
3065
3066 UNGCPRO;
3067 return attrs;
3068}
91c85b70 3069
f4f634e8
DN
3070#elif defined (SOLARIS2) && defined (HAVE_PROCFS)
3071
3072/* The <procfs.h> header does not like to be included if _LP64 is defined and
3073 __FILE_OFFSET_BITS == 64. This is an ugly workaround that. */
3074#if !defined (_LP64) && defined (_FILE_OFFSET_BITS) && (_FILE_OFFSET_BITS == 64)
3075#define PROCFS_FILE_OFFSET_BITS_HACK 1
3076#undef _FILE_OFFSET_BITS
3077#else
3078#define PROCFS_FILE_OFFSET_BITS_HACK 0
3079#endif
3080
3081#include <procfs.h>
3082
3083#if PROCFS_FILE_OFFSET_BITS_HACK == 1
3084#define _FILE_OFFSET_BITS 64
90efadd1
PE
3085#ifdef _FILE_OFFSET_BITS /* Avoid unused-macro warnings. */
3086#endif
f4f634e8
DN
3087#endif /* PROCFS_FILE_OFFSET_BITS_HACK == 1 */
3088
3089Lisp_Object
3090system_process_attributes (Lisp_Object pid)
3091{
3092 char procfn[PATH_MAX], fn[PATH_MAX];
3093 struct stat st;
3094 struct passwd *pw;
3095 struct group *gr;
3096 char *procfn_end;
3097 struct psinfo pinfo;
3098 int fd;
3099 ssize_t nread;
d311d28c
PE
3100 printmax_t proc_id;
3101 uid_t uid;
3102 gid_t gid;
f4f634e8
DN
3103 Lisp_Object attrs = Qnil;
3104 Lisp_Object decoded_cmd, tem;
3105 struct gcpro gcpro1, gcpro2;
f4f634e8
DN
3106
3107 CHECK_NUMBER_OR_FLOAT (pid);
225a2cff 3108 CONS_TO_INTEGER (pid, pid_t, proc_id);
d311d28c 3109 sprintf (procfn, "/proc/%"pMd, proc_id);
f4f634e8
DN
3110 if (stat (procfn, &st) < 0)
3111 return attrs;
3112
3113 GCPRO2 (attrs, decoded_cmd);
3114
3115 /* euid egid */
3116 uid = st.st_uid;
d311d28c 3117 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (uid)), attrs);
4d7e6e51 3118 block_input ();
f4f634e8 3119 pw = getpwuid (uid);
4d7e6e51 3120 unblock_input ();
f4f634e8
DN
3121 if (pw)
3122 attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
3123
3124 gid = st.st_gid;
d311d28c 3125 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (gid)), attrs);
4d7e6e51 3126 block_input ();
f4f634e8 3127 gr = getgrgid (gid);
4d7e6e51 3128 unblock_input ();
f4f634e8
DN
3129 if (gr)
3130 attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
3131
3132 strcpy (fn, procfn);
3133 procfn_end = fn + strlen (fn);
3134 strcpy (procfn_end, "/psinfo");
3135 fd = emacs_open (fn, O_RDONLY, 0);
3136 if (fd >= 0
cf84bb53 3137 && (nread = read (fd, (char*)&pinfo, sizeof (struct psinfo)) > 0))
f4f634e8
DN
3138 {
3139 attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (pinfo.pr_ppid)), attrs);
3140 attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (pinfo.pr_pgid)), attrs);
3141 attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (pinfo.pr_sid)), attrs);
3142
3143 {
3144 char state_str[2];
3145 state_str[0] = pinfo.pr_lwp.pr_sname;
3146 state_str[1] = '\0';
3147 tem = build_string (state_str);
3148 attrs = Fcons (Fcons (Qstate, tem), attrs);
3149 }
3150
3151 /* FIXME: missing Qttyname. psinfo.pr_ttydev is a dev_t,
3152 need to get a string from it. */
3153
3154 /* FIXME: missing: Qtpgid */
3155
3156 /* FIXME: missing:
3157 Qminflt
3158 Qmajflt
3159 Qcminflt
3160 Qcmajflt
3161
bfe11752
DN
3162 Qutime
3163 Qcutime
f4f634e8
DN
3164 Qstime
3165 Qcstime
3166 Are they available? */
3167
d35af63c
PE
3168 attrs = Fcons (Fcons (Qtime, make_lisp_time (pinfo.pr_time)), attrs);
3169 attrs = Fcons (Fcons (Qctime, make_lisp_time (pinfo.pr_ctime)), attrs);
f4f634e8
DN
3170 attrs = Fcons (Fcons (Qpri, make_number (pinfo.pr_lwp.pr_pri)), attrs);
3171 attrs = Fcons (Fcons (Qnice, make_number (pinfo.pr_lwp.pr_nice)), attrs);
3172 attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (pinfo.pr_nlwp)), attrs);
3173
d35af63c 3174 attrs = Fcons (Fcons (Qstart, make_lisp_time (pinfo.pr_start)), attrs);
f4f634e8
DN
3175 attrs = Fcons (Fcons (Qvsize, make_fixnum_or_float (pinfo.pr_size)), attrs);
3176 attrs = Fcons (Fcons (Qrss, make_fixnum_or_float (pinfo.pr_rssize)), attrs);
3177
773d47f6
PE
3178 /* pr_pctcpu and pr_pctmem are unsigned integers in the
3179 range 0 .. 2**15, representing 0.0 .. 1.0. */
63810350
PE
3180 attrs = Fcons (Fcons (Qpcpu, make_float (100.0 / 0x8000 * pinfo.pr_pctcpu)), attrs);
3181 attrs = Fcons (Fcons (Qpmem, make_float (100.0 / 0x8000 * pinfo.pr_pctmem)), attrs);
f4f634e8
DN
3182
3183 decoded_cmd
3184 = code_convert_string_norecord (make_unibyte_string (pinfo.pr_fname,
3185 strlen (pinfo.pr_fname)),
3186 Vlocale_coding_system, 0);
3187 attrs = Fcons (Fcons (Qcomm, decoded_cmd), attrs);
3188 decoded_cmd
3189 = code_convert_string_norecord (make_unibyte_string (pinfo.pr_psargs,
3190 strlen (pinfo.pr_psargs)),
3191 Vlocale_coding_system, 0);
3192 attrs = Fcons (Fcons (Qargs, decoded_cmd), attrs);
3193 }
3194
2d2d05d8
DN
3195 if (fd >= 0)
3196 emacs_close (fd);
3197
f4f634e8
DN
3198 UNGCPRO;
3199 return attrs;
3200}
06e111a6 3201
5790543d 3202#elif defined __FreeBSD__
b91b7e4d 3203
d054f3fb
PE
3204static EMACS_TIME
3205timeval_to_EMACS_TIME (struct timeval t)
3206{
e9a9ae03 3207 return make_emacs_time (t.tv_sec, t.tv_usec * 1000);
d054f3fb
PE
3208}
3209
3210static Lisp_Object
db7b8d06 3211make_lisp_timeval (struct timeval t)
d054f3fb
PE
3212{
3213 return make_lisp_time (timeval_to_EMACS_TIME (t));
3214}
3215
b91b7e4d
EW
3216Lisp_Object
3217system_process_attributes (Lisp_Object pid)
3218{
3219 int proc_id;
5790543d 3220 int pagesize = getpagesize ();
b91b7e4d
EW
3221 int npages;
3222 int fscale;
3223 struct passwd *pw;
3224 struct group *gr;
3225 char *ttyname;
3226 size_t len;
3227 char args[MAXPATHLEN];
3228 EMACS_TIME t, now;
5790543d 3229
b91b7e4d
EW
3230 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID};
3231 struct kinfo_proc proc;
5790543d 3232 size_t proclen = sizeof proc;
b91b7e4d
EW
3233
3234 struct gcpro gcpro1, gcpro2;
3235 Lisp_Object attrs = Qnil;
3236 Lisp_Object decoded_comm;
5790543d 3237
b91b7e4d 3238 CHECK_NUMBER_OR_FLOAT (pid);
af52196c 3239 CONS_TO_INTEGER (pid, int, proc_id);
b91b7e4d 3240 mib[3] = proc_id;
5790543d 3241
b91b7e4d
EW
3242 if (sysctl (mib, 4, &proc, &proclen, NULL, 0) != 0)
3243 return attrs;
3244
3245 GCPRO2 (attrs, decoded_comm);
5790543d
PE
3246
3247 attrs = Fcons (Fcons (Qeuid, make_fixnum_or_float (proc.ki_uid)), attrs);
3248
4d7e6e51 3249 block_input ();
b91b7e4d 3250 pw = getpwuid (proc.ki_uid);
4d7e6e51 3251 unblock_input ();
b91b7e4d
EW
3252 if (pw)
3253 attrs = Fcons (Fcons (Quser, build_string (pw->pw_name)), attrs);
3254
5790543d 3255 attrs = Fcons (Fcons (Qegid, make_fixnum_or_float (proc.ki_svgid)), attrs);
b91b7e4d 3256
4d7e6e51 3257 block_input ();
b91b7e4d 3258 gr = getgrgid (proc.ki_svgid);
4d7e6e51 3259 unblock_input ();
b91b7e4d
EW
3260 if (gr)
3261 attrs = Fcons (Fcons (Qgroup, build_string (gr->gr_name)), attrs);
3262
3263 decoded_comm = code_convert_string_norecord
3264 (make_unibyte_string (proc.ki_comm, strlen (proc.ki_comm)),
3265 Vlocale_coding_system, 0);
5790543d 3266
b91b7e4d
EW
3267 attrs = Fcons (Fcons (Qcomm, decoded_comm), attrs);
3268 {
3269 char state[2] = {'\0', '\0'};
3270 switch (proc.ki_stat)
3271 {
3272 case SRUN:
3273 state[0] = 'R';
3274 break;
3275
3276 case SSLEEP:
3277 state[0] = 'S';
3278 break;
5790543d 3279
b91b7e4d
EW
3280 case SLOCK:
3281 state[0] = 'D';
3282 break;
3283
3284 case SZOMB:
3285 state[0] = 'Z';
3286 break;
5790543d 3287
b91b7e4d
EW
3288 case SSTOP:
3289 state[0] = 'T';
3290 break;
3291 }
3292 attrs = Fcons (Fcons (Qstate, build_string (state)), attrs);
3293 }
5790543d 3294
b91b7e4d
EW
3295 attrs = Fcons (Fcons (Qppid, make_fixnum_or_float (proc.ki_ppid)), attrs);
3296 attrs = Fcons (Fcons (Qpgrp, make_fixnum_or_float (proc.ki_pgid)), attrs);
3297 attrs = Fcons (Fcons (Qsess, make_fixnum_or_float (proc.ki_sid)), attrs);
3298
4d7e6e51 3299 block_input ();
b91b7e4d 3300 ttyname = proc.ki_tdev == NODEV ? NULL : devname (proc.ki_tdev, S_IFCHR);
4d7e6e51 3301 unblock_input ();
b91b7e4d
EW
3302 if (ttyname)
3303 attrs = Fcons (Fcons (Qtty, build_string (ttyname)), attrs);
5790543d 3304
b91b7e4d
EW
3305 attrs = Fcons (Fcons (Qtpgid, make_fixnum_or_float (proc.ki_tpgid)), attrs);
3306 attrs = Fcons (Fcons (Qminflt, make_fixnum_or_float (proc.ki_rusage.ru_minflt)), attrs);
3307 attrs = Fcons (Fcons (Qmajflt, make_fixnum_or_float (proc.ki_rusage.ru_majflt)), attrs);
3308 attrs = Fcons (Fcons (Qcminflt, make_number (proc.ki_rusage_ch.ru_minflt)), attrs);
3309 attrs = Fcons (Fcons (Qcmajflt, make_number (proc.ki_rusage_ch.ru_majflt)), attrs);
3310
db7b8d06
PE
3311 attrs = Fcons (Fcons (Qutime, make_lisp_timeval (proc.ki_rusage.ru_utime)),
3312 attrs);
3313 attrs = Fcons (Fcons (Qstime, make_lisp_timeval (proc.ki_rusage.ru_stime)),
3314 attrs);
e9a9ae03
PE
3315 t = add_emacs_time (timeval_to_EMACS_TIME (proc.ki_rusage.ru_utime),
3316 timeval_to_EMACS_TIME (proc.ki_rusage.ru_stime));
db7b8d06 3317 attrs = Fcons (Fcons (Qtime, make_lisp_time (t)), attrs);
b91b7e4d 3318
db7b8d06
PE
3319 attrs = Fcons (Fcons (Qcutime,
3320 make_lisp_timeval (proc.ki_rusage_ch.ru_utime)),
3321 attrs);
3322 attrs = Fcons (Fcons (Qcstime,
3323 make_lisp_timeval (proc.ki_rusage_ch.ru_utime)),
3324 attrs);
e9a9ae03
PE
3325 t = add_emacs_time (timeval_to_EMACS_TIME (proc.ki_rusage_ch.ru_utime),
3326 timeval_to_EMACS_TIME (proc.ki_rusage_ch.ru_stime));
db7b8d06 3327 attrs = Fcons (Fcons (Qctime, make_lisp_time (t)), attrs);
b91b7e4d 3328
5790543d
PE
3329 attrs = Fcons (Fcons (Qthcount, make_fixnum_or_float (proc.ki_numthreads)),
3330 attrs);
b91b7e4d
EW
3331 attrs = Fcons (Fcons (Qpri, make_number (proc.ki_pri.pri_native)), attrs);
3332 attrs = Fcons (Fcons (Qnice, make_number (proc.ki_nice)), attrs);
db7b8d06 3333 attrs = Fcons (Fcons (Qstart, make_lisp_timeval (proc.ki_start)), attrs);
b91b7e4d 3334 attrs = Fcons (Fcons (Qvsize, make_number (proc.ki_size >> 10)), attrs);
5790543d
PE
3335 attrs = Fcons (Fcons (Qrss, make_number (proc.ki_rssize * pagesize >> 10)),
3336 attrs);
b91b7e4d 3337
e9a9ae03
PE
3338 now = current_emacs_time ();
3339 t = sub_emacs_time (now, timeval_to_EMACS_TIME (proc.ki_start));
db7b8d06 3340 attrs = Fcons (Fcons (Qetime, make_lisp_time (t)), attrs);
b91b7e4d 3341
5790543d 3342 len = sizeof fscale;
b91b7e4d
EW
3343 if (sysctlbyname ("kern.fscale", &fscale, &len, NULL, 0) == 0)
3344 {
5790543d 3345 double pcpu;
b91b7e4d 3346 fixpt_t ccpu;
5790543d 3347 len = sizeof ccpu;
b91b7e4d
EW
3348 if (sysctlbyname ("kern.ccpu", &ccpu, &len, NULL, 0) == 0)
3349 {
5790543d
PE
3350 pcpu = (100.0 * proc.ki_pctcpu / fscale
3351 / (1 - exp (proc.ki_swtime * log ((double) ccpu / fscale))));
3352 attrs = Fcons (Fcons (Qpcpu, make_fixnum_or_float (pcpu)), attrs);
b91b7e4d
EW
3353 }
3354 }
3355
5790543d 3356 len = sizeof npages;
b91b7e4d
EW
3357 if (sysctlbyname ("hw.availpages", &npages, &len, NULL, 0) == 0)
3358 {
5790543d
PE
3359 double pmem = (proc.ki_flag & P_INMEM
3360 ? 100.0 * proc.ki_rssize / npages
3361 : 0);
3362 attrs = Fcons (Fcons (Qpmem, make_fixnum_or_float (pmem)), attrs);
b91b7e4d
EW
3363 }
3364
3365 mib[2] = KERN_PROC_ARGS;
3366 len = MAXPATHLEN;
3367 if (sysctl (mib, 4, args, &len, NULL, 0) == 0)
3368 {
3369 int i;
3370 for (i = 0; i < len; i++)
3371 {
3372 if (! args[i] && i < len - 1)
3373 args[i] = ' ';
3374 }
3375
5790543d
PE
3376 decoded_comm =
3377 (code_convert_string_norecord
d7ea76b4 3378 (build_unibyte_string (args),
5790543d 3379 Vlocale_coding_system, 0));
b91b7e4d
EW
3380
3381 attrs = Fcons (Fcons (Qargs, decoded_comm), attrs);
3382 }
5790543d 3383
b91b7e4d
EW
3384 UNGCPRO;
3385 return attrs;
3386}
3387
f8d23104
DN
3388/* The WINDOWSNT implementation is in w32.c.
3389 The MSDOS implementation is in dosfns.c. */
c4605e09 3390#elif !defined (WINDOWSNT) && !defined (MSDOS)
06e111a6
DN
3391
3392Lisp_Object
3393system_process_attributes (Lisp_Object pid)
3394{
9dcbe89b 3395 return Qnil;
06e111a6
DN
3396}
3397
3398#endif /* !defined (WINDOWSNT) */