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