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