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