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