*** empty log message ***
[bpt/guile.git] / libguile / posix.c
CommitLineData
d675a50f 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2003, 2004 Free Software Foundation, Inc.
0f2d19dd 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
0f2d19dd 7 *
73be1d9e
MV
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
0f2d19dd 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 */
1bbd0b84 17
1bbd0b84 18
0f2d19dd 19\f
2546b5c3
RB
20#if HAVE_CONFIG_H
21# include <config.h>
22#endif
0f2d19dd 23
8b50fe8e
MV
24/* Make GNU/Linux libc declare everything it has. */
25#define _GNU_SOURCE
26
0f2d19dd 27#include <stdio.h>
e6e2e95a
MD
28#include <errno.h>
29
a0599745 30#include "libguile/_scm.h"
b28f5b3c 31#include "libguile/dynwind.h"
a0599745
MD
32#include "libguile/fports.h"
33#include "libguile/scmsigs.h"
34#include "libguile/feature.h"
35#include "libguile/strings.h"
c44ca4fe 36#include "libguile/srfi-13.h"
a0599745 37#include "libguile/vectors.h"
c96d76b8 38#include "libguile/lang.h"
a0599745
MD
39
40#include "libguile/validate.h"
41#include "libguile/posix.h"
9361f762 42#include "libguile/i18n.h"
0f2d19dd
JB
43\f
44
02b754d3
GH
45#ifdef HAVE_STRING_H
46#include <string.h>
47#endif
0f2d19dd
JB
48#ifdef TIME_WITH_SYS_TIME
49# include <sys/time.h>
50# include <time.h>
51#else
52# if HAVE_SYS_TIME_H
53# include <sys/time.h>
54# else
55# include <time.h>
56# endif
57#endif
58
59#ifdef HAVE_UNISTD_H
60#include <unistd.h>
95b88819
GH
61#else
62#ifndef ttyname
63extern char *ttyname();
64#endif
0f2d19dd
JB
65#endif
66
3594582b 67#ifdef LIBC_H_WITH_UNISTD_H
bab0f4e5
JB
68#include <libc.h>
69#endif
70
8cc71382 71#include <sys/types.h>
0f2d19dd
JB
72#include <sys/stat.h>
73#include <fcntl.h>
74
82893676 75#ifdef HAVE_PWD_H
0f2d19dd 76#include <pwd.h>
82893676
MG
77#endif
78#ifdef HAVE_IO_H
79#include <io.h>
80#endif
f87c105a 81#ifdef HAVE_WINSOCK2_H
82893676
MG
82#include <winsock2.h>
83#endif
84
85#ifdef __MINGW32__
86/* Some defines for Windows here. */
7beabedb 87# include <process.h>
82893676
MG
88# define pipe(fd) _pipe (fd, 256, O_BINARY)
89#endif /* __MINGW32__ */
0f2d19dd
JB
90
91#if HAVE_SYS_WAIT_H
92# include <sys/wait.h>
93#endif
94#ifndef WEXITSTATUS
95# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
96#endif
97#ifndef WIFEXITED
98# define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
99#endif
100
101#include <signal.h>
102
0f2d19dd
JB
103extern char ** environ;
104
82893676 105#ifdef HAVE_GRP_H
0f2d19dd 106#include <grp.h>
82893676
MG
107#endif
108#ifdef HAVE_SYS_UTSNAME_H
0f2d19dd 109#include <sys/utsname.h>
82893676 110#endif
0f2d19dd 111
0f2d19dd
JB
112#ifdef HAVE_SETLOCALE
113#include <locale.h>
114#endif
115
b9a7b725 116#if HAVE_CRYPT_H
94e6d793
MG
117# include <crypt.h>
118#endif
119
0eaf1055
KR
120#ifdef HAVE_NETDB_H
121#include <netdb.h> /* for MAXHOSTNAMELEN on Solaris */
122#endif
123
124#ifdef HAVE_SYS_PARAM_H
125#include <sys/param.h> /* for MAXHOSTNAMELEN */
126#endif
127
94e6d793
MG
128#if HAVE_SYS_RESOURCE_H
129# include <sys/resource.h>
130#endif
131
132#if HAVE_SYS_FILE_H
133# include <sys/file.h>
134#endif
135
eb7e1603
KR
136#if HAVE_CRT_EXTERNS_H
137#include <crt_externs.h> /* for Darwin _NSGetEnviron */
138#endif
139
bab0f4e5
JB
140/* Some Unix systems don't define these. CPP hair is dangerous, but
141 this seems safe enough... */
142#ifndef R_OK
143#define R_OK 4
144#endif
145
146#ifndef W_OK
147#define W_OK 2
148#endif
149
150#ifndef X_OK
151#define X_OK 1
152#endif
153
154#ifndef F_OK
155#define F_OK 0
156#endif
398609a5
JB
157
158/* On NextStep, <utime.h> doesn't define struct utime, unless we
159 #define _POSIX_SOURCE before #including it. I think this is less
160 of a kludge than defining struct utimbuf ourselves. */
161#ifdef UTIMBUF_NEEDS_POSIX
162#define _POSIX_SOURCE
163#endif
164
165#ifdef HAVE_SYS_UTIME_H
166#include <sys/utime.h>
167#endif
168
169#ifdef HAVE_UTIME_H
170#include <utime.h>
171#endif
172
173/* Please don't add any more #includes or #defines here. The hack
174 above means that _POSIX_SOURCE may be #defined, which will
eb7e1603
KR
175 encourage header files to do strange things.
176
177 FIXME: Maybe should undef _POSIX_SOURCE after it's done its job.
178
179 FIXME: Probably should do all the includes first, then all the fallback
180 declarations and defines, in case things are not in the header we
181 imagine. */
182
183
184
185
186/* On Apple Darwin in a shared library there's no "environ" to access
187 directly, instead the address of that variable must be obtained with
188 _NSGetEnviron(). */
189#if HAVE__NSGETENVIRON && defined (PIC)
190#define environ (*_NSGetEnviron())
191#endif
398609a5 192
0f2d19dd 193\f
f015614a
MV
194
195/* Two often used patterns
196 */
197
198#define WITH_STRING(str,cstr,code) \
199 do { \
200 char *cstr = scm_to_locale_string (str); \
201 code; \
202 free (cstr); \
203 } while (0)
204
205#define STRING_SYSCALL(str,cstr,code) \
206 do { \
207 int eno; \
208 char *cstr = scm_to_locale_string (str); \
209 SCM_SYSCALL (code); \
210 eno = errno; free (cstr); errno = eno; \
211 } while (0)
212
213
214\f
bc45012d
JB
215SCM_SYMBOL (sym_read_pipe, "read pipe");
216SCM_SYMBOL (sym_write_pipe, "write pipe");
0f2d19dd 217
a1ec6916 218SCM_DEFINE (scm_pipe, "pipe", 0, 0, 0,
1bbd0b84 219 (),
1e6808ea
MG
220 "Return a newly created pipe: a pair of ports which are linked\n"
221 "together on the local machine. The @emph{car} is the input\n"
222 "port and the @emph{cdr} is the output port. Data written (and\n"
223 "flushed) to the output port can be read from the input port.\n"
224 "Pipes are commonly used for communication with a newly forked\n"
225 "child process. The need to flush the output port can be\n"
226 "avoided by making it unbuffered using @code{setvbuf}.\n"
227 "\n"
228 "Writes occur atomically provided the size of the data in bytes\n"
229 "is not greater than the value of @code{PIPE_BUF}. Note that\n"
230 "the output port is likely to block if too much data (typically\n"
231 "equal to @code{PIPE_BUF}) has been written but not yet read\n"
232 "from the input port.")
1bbd0b84 233#define FUNC_NAME s_scm_pipe
0f2d19dd
JB
234{
235 int fd[2], rv;
0f2d19dd 236 SCM p_rd, p_wt;
02b754d3 237
0f2d19dd
JB
238 rv = pipe (fd);
239 if (rv)
1bbd0b84 240 SCM_SYSERROR;
ee149d03
JB
241
242 p_rd = scm_fdes_to_port (fd[0], "r", sym_read_pipe);
243 p_wt = scm_fdes_to_port (fd[1], "w", sym_write_pipe);
0f2d19dd
JB
244 return scm_cons (p_rd, p_wt);
245}
1bbd0b84 246#undef FUNC_NAME
0f2d19dd
JB
247
248
0e958795 249#ifdef HAVE_GETGROUPS
a1ec6916 250SCM_DEFINE (scm_getgroups, "getgroups", 0, 0, 0,
1bbd0b84 251 (),
1e6808ea 252 "Return a vector of integers representing the current\n"
bb2c02f2 253 "supplementary group IDs.")
1bbd0b84 254#define FUNC_NAME s_scm_getgroups
0f2d19dd 255{
1d1559ce 256 SCM result;
66460dfb 257 int ngroups;
1be6b49c 258 size_t size;
66460dfb
DH
259 GETGROUPS_T *groups;
260
261 ngroups = getgroups (0, NULL);
262 if (ngroups <= 0)
1bbd0b84 263 SCM_SYSERROR;
66460dfb
DH
264
265 size = ngroups * sizeof (GETGROUPS_T);
4c9419ac 266 groups = scm_malloc (size);
66460dfb
DH
267 getgroups (ngroups, groups);
268
f360a962
MV
269 result = scm_c_make_vector (ngroups, SCM_BOOL_F);
270 while (--ngroups >= 0)
b9bd8526 271 SCM_VECTOR_SET (result, ngroups, scm_from_ulong (groups[ngroups]));
66460dfb 272
4c9419ac 273 free (groups);
1d1559ce 274 return result;
1bbd0b84
GB
275}
276#undef FUNC_NAME
0e958795 277#endif
0f2d19dd 278
f360a962
MV
279#ifdef HAVE_SETGROUPS
280SCM_DEFINE (scm_setgroups, "setgroups", 1, 0, 0,
281 (SCM group_vec),
fcc3adc2
KR
282 "Set the current set of supplementary group IDs to the integers\n"
283 "in the given vector @var{vec}. The return value is\n"
284 "unspecified.\n"
285 "\n"
286 "Generally only the superuser can set the process group IDs.")
f360a962
MV
287#define FUNC_NAME s_scm_setgroups
288{
289 size_t ngroups;
290 size_t size;
291 size_t i;
292 int result;
293 int save_errno;
294 GETGROUPS_T *groups;
295
296 SCM_VALIDATE_VECTOR (SCM_ARG1, group_vec);
297
298 ngroups = SCM_VECTOR_LENGTH (group_vec);
299
300 /* validate before allocating, so we don't have to worry about leaks */
301 for (i = 0; i < ngroups; i++)
302 {
303 unsigned long ulong_gid;
304 GETGROUPS_T gid;
305 SCM_VALIDATE_ULONG_COPY (1, SCM_VECTOR_REF (group_vec, i), ulong_gid);
306 gid = ulong_gid;
307 if (gid != ulong_gid)
308 SCM_OUT_OF_RANGE (1, SCM_VECTOR_REF (group_vec, i));
309 }
310
311 size = ngroups * sizeof (GETGROUPS_T);
2eb78d06 312 if (size / sizeof (GETGROUPS_T) != ngroups)
e11e83f3 313 SCM_OUT_OF_RANGE (SCM_ARG1, scm_from_int (ngroups));
f360a962
MV
314 groups = scm_malloc (size);
315 for(i = 0; i < ngroups; i++)
316 groups [i] = SCM_NUM2ULONG (1, SCM_VECTOR_REF (group_vec, i));
317
318 result = setgroups (ngroups, groups);
319 save_errno = errno; /* don't let free() touch errno */
320 free (groups);
321 errno = save_errno;
322 if (result < 0)
323 SCM_SYSERROR;
324 return SCM_UNSPECIFIED;
325}
326#undef FUNC_NAME
327#endif
328
82893676 329#ifdef HAVE_GETPWENT
a1ec6916 330SCM_DEFINE (scm_getpwuid, "getpw", 0, 1, 0,
1bbd0b84 331 (SCM user),
b380b885
MD
332 "Look up an entry in the user database. @var{obj} can be an integer,\n"
333 "a string, or omitted, giving the behaviour of getpwuid, getpwnam\n"
334 "or getpwent respectively.")
1bbd0b84 335#define FUNC_NAME s_scm_getpwuid
0f2d19dd 336{
0f2d19dd 337 struct passwd *entry;
0f2d19dd 338
1d1559ce 339 SCM result = scm_c_make_vector (7, SCM_UNSPECIFIED);
7888309b 340 if (SCM_UNBNDP (user) || scm_is_false (user))
0f2d19dd 341 {
0f2d19dd 342 SCM_SYSCALL (entry = getpwent ());
3d781d49
JB
343 if (! entry)
344 {
3d781d49
JB
345 return SCM_BOOL_F;
346 }
0f2d19dd 347 }
e11e83f3 348 else if (scm_is_integer (user))
0f2d19dd 349 {
e11e83f3 350 entry = getpwuid (scm_to_int (user));
0f2d19dd
JB
351 }
352 else
353 {
f015614a
MV
354 WITH_STRING (user, c_user,
355 entry = getpwnam (c_user));
0f2d19dd
JB
356 }
357 if (!entry)
1bbd0b84 358 SCM_MISC_ERROR ("entry not found", SCM_EOL);
02b754d3 359
cc95e00a
MV
360 SCM_VECTOR_SET(result, 0, scm_from_locale_string (entry->pw_name));
361 SCM_VECTOR_SET(result, 1, scm_from_locale_string (entry->pw_passwd));
b9bd8526
MV
362 SCM_VECTOR_SET(result, 2, scm_from_ulong (entry->pw_uid));
363 SCM_VECTOR_SET(result, 3, scm_from_ulong (entry->pw_gid));
cc95e00a 364 SCM_VECTOR_SET(result, 4, scm_from_locale_string (entry->pw_gecos));
0f2d19dd 365 if (!entry->pw_dir)
cc95e00a 366 SCM_VECTOR_SET(result, 5, scm_from_locale_string (""));
0f2d19dd 367 else
cc95e00a 368 SCM_VECTOR_SET(result, 5, scm_from_locale_string (entry->pw_dir));
0f2d19dd 369 if (!entry->pw_shell)
cc95e00a 370 SCM_VECTOR_SET(result, 6, scm_from_locale_string (""));
0f2d19dd 371 else
cc95e00a 372 SCM_VECTOR_SET(result, 6, scm_from_locale_string (entry->pw_shell));
1d1559ce 373 return result;
0f2d19dd 374}
1bbd0b84 375#undef FUNC_NAME
82893676 376#endif /* HAVE_GETPWENT */
0f2d19dd
JB
377
378
0e958795 379#ifdef HAVE_SETPWENT
a1ec6916 380SCM_DEFINE (scm_setpwent, "setpw", 0, 1, 0,
1bbd0b84 381 (SCM arg),
b380b885
MD
382 "If called with a true argument, initialize or reset the password data\n"
383 "stream. Otherwise, close the stream. The @code{setpwent} and\n"
384 "@code{endpwent} procedures are implemented on top of this.")
1bbd0b84 385#define FUNC_NAME s_scm_setpwent
0f2d19dd 386{
7888309b 387 if (SCM_UNBNDP (arg) || scm_is_false (arg))
0f2d19dd
JB
388 endpwent ();
389 else
390 setpwent ();
391 return SCM_UNSPECIFIED;
392}
1bbd0b84 393#undef FUNC_NAME
0e958795 394#endif
0f2d19dd
JB
395
396
82893676 397#ifdef HAVE_GETGRENT
0f2d19dd 398/* Combines getgrgid and getgrnam. */
a1ec6916 399SCM_DEFINE (scm_getgrgid, "getgr", 0, 1, 0,
1bbd0b84 400 (SCM name),
b380b885
MD
401 "Look up an entry in the group database. @var{obj} can be an integer,\n"
402 "a string, or omitted, giving the behaviour of getgrgid, getgrnam\n"
403 "or getgrent respectively.")
1bbd0b84 404#define FUNC_NAME s_scm_getgrgid
0f2d19dd 405{
0f2d19dd 406 struct group *entry;
1d1559ce 407 SCM result = scm_c_make_vector (4, SCM_UNSPECIFIED);
34d19ef6 408
7888309b 409 if (SCM_UNBNDP (name) || scm_is_false (name))
3d781d49
JB
410 {
411 SCM_SYSCALL (entry = getgrent ());
412 if (! entry)
413 {
3d781d49
JB
414 return SCM_BOOL_F;
415 }
416 }
e11e83f3
MV
417 else if (scm_is_integer (name))
418 SCM_SYSCALL (entry = getgrgid (scm_to_int (name)));
0f2d19dd 419 else
f015614a
MV
420 STRING_SYSCALL (name, c_name,
421 entry = getgrnam (c_name));
0f2d19dd 422 if (!entry)
1bbd0b84 423 SCM_SYSERROR;
02b754d3 424
cc95e00a
MV
425 SCM_VECTOR_SET(result, 0, scm_from_locale_string (entry->gr_name));
426 SCM_VECTOR_SET(result, 1, scm_from_locale_string (entry->gr_passwd));
b9bd8526 427 SCM_VECTOR_SET(result, 2, scm_from_ulong (entry->gr_gid));
1d1559ce
HWN
428 SCM_VECTOR_SET(result, 3, scm_makfromstrs (-1, entry->gr_mem));
429 return result;
0f2d19dd 430}
1bbd0b84 431#undef FUNC_NAME
0f2d19dd
JB
432
433
434
a1ec6916 435SCM_DEFINE (scm_setgrent, "setgr", 0, 1, 0,
1bbd0b84 436 (SCM arg),
b380b885
MD
437 "If called with a true argument, initialize or reset the group data\n"
438 "stream. Otherwise, close the stream. The @code{setgrent} and\n"
439 "@code{endgrent} procedures are implemented on top of this.")
1bbd0b84 440#define FUNC_NAME s_scm_setgrent
0f2d19dd 441{
7888309b 442 if (SCM_UNBNDP (arg) || scm_is_false (arg))
0f2d19dd
JB
443 endgrent ();
444 else
445 setgrent ();
446 return SCM_UNSPECIFIED;
447}
1bbd0b84 448#undef FUNC_NAME
82893676 449#endif /* HAVE_GETGRENT */
0f2d19dd
JB
450
451
a1ec6916 452SCM_DEFINE (scm_kill, "kill", 2, 0, 0,
1bbd0b84 453 (SCM pid, SCM sig),
b380b885
MD
454 "Sends a signal to the specified process or group of processes.\n\n"
455 "@var{pid} specifies the processes to which the signal is sent:\n\n"
456 "@table @r\n"
457 "@item @var{pid} greater than 0\n"
458 "The process whose identifier is @var{pid}.\n"
459 "@item @var{pid} equal to 0\n"
460 "All processes in the current process group.\n"
461 "@item @var{pid} less than -1\n"
462 "The process group whose identifier is -@var{pid}\n"
463 "@item @var{pid} equal to -1\n"
464 "If the process is privileged, all processes except for some special\n"
465 "system processes. Otherwise, all processes with the current effective\n"
466 "user ID.\n"
467 "@end table\n\n"
468 "@var{sig} should be specified using a variable corresponding to\n"
469 "the Unix symbolic name, e.g.,\n\n"
470 "@defvar SIGHUP\n"
471 "Hang-up signal.\n"
472 "@end defvar\n\n"
473 "@defvar SIGINT\n"
474 "Interrupt signal.\n"
475 "@end defvar")
1bbd0b84 476#define FUNC_NAME s_scm_kill
0f2d19dd 477{
0f2d19dd 478 /* Signal values are interned in scm_init_posix(). */
82893676 479#ifdef HAVE_KILL
a55c2b68 480 if (kill (scm_to_int (pid), scm_to_int (sig)) != 0)
82893676 481#else
a55c2b68
MV
482 if (scm_to_int (pid) == getpid ())
483 if (raise (scm_to_int (sig)) != 0)
82893676
MG
484#endif
485 SCM_SYSERROR;
02b754d3 486 return SCM_UNSPECIFIED;
0f2d19dd 487}
1bbd0b84 488#undef FUNC_NAME
0f2d19dd 489
d00ae47e 490#ifdef HAVE_WAITPID
a1ec6916 491SCM_DEFINE (scm_waitpid, "waitpid", 1, 1, 0,
1bbd0b84 492 (SCM pid, SCM options),
b380b885
MD
493 "This procedure collects status information from a child process which\n"
494 "has terminated or (optionally) stopped. Normally it will\n"
495 "suspend the calling process until this can be done. If more than one\n"
496 "child process is eligible then one will be chosen by the operating system.\n\n"
497 "The value of @var{pid} determines the behaviour:\n\n"
498 "@table @r\n"
499 "@item @var{pid} greater than 0\n"
500 "Request status information from the specified child process.\n"
501 "@item @var{pid} equal to -1 or WAIT_ANY\n"
502 "Request status information for any child process.\n"
503 "@item @var{pid} equal to 0 or WAIT_MYPGRP\n"
504 "Request status information for any child process in the current process\n"
505 "group.\n"
506 "@item @var{pid} less than -1\n"
507 "Request status information for any child process whose process group ID\n"
508 "is -@var{PID}.\n"
509 "@end table\n\n"
510 "The @var{options} argument, if supplied, should be the bitwise OR of the\n"
511 "values of zero or more of the following variables:\n\n"
512 "@defvar WNOHANG\n"
513 "Return immediately even if there are no child processes to be collected.\n"
514 "@end defvar\n\n"
515 "@defvar WUNTRACED\n"
516 "Report status information for stopped processes as well as terminated\n"
517 "processes.\n"
518 "@end defvar\n\n"
519 "The return value is a pair containing:\n\n"
520 "@enumerate\n"
521 "@item\n"
522 "The process ID of the child process, or 0 if @code{WNOHANG} was\n"
523 "specified and no process was collected.\n"
524 "@item\n"
525 "The integer status value.\n"
526 "@end enumerate")
1bbd0b84 527#define FUNC_NAME s_scm_waitpid
0f2d19dd
JB
528{
529 int i;
530 int status;
531 int ioptions;
0f2d19dd
JB
532 if (SCM_UNBNDP (options))
533 ioptions = 0;
534 else
535 {
0f2d19dd 536 /* Flags are interned in scm_init_posix. */
a55c2b68 537 ioptions = scm_to_int (options);
0f2d19dd 538 }
a55c2b68 539 SCM_SYSCALL (i = waitpid (scm_to_int (pid), &status, ioptions));
02b754d3 540 if (i == -1)
1bbd0b84 541 SCM_SYSERROR;
a55c2b68 542 return scm_cons (scm_from_int (i), scm_from_int (status));
0f2d19dd 543}
1bbd0b84 544#undef FUNC_NAME
d00ae47e 545#endif /* HAVE_WAITPID */
0f2d19dd 546
82893676 547#ifndef __MINGW32__
a1ec6916 548SCM_DEFINE (scm_status_exit_val, "status:exit-val", 1, 0, 0,
1bbd0b84 549 (SCM status),
1e6808ea
MG
550 "Return the exit status value, as would be set if a process\n"
551 "ended normally through a call to @code{exit} or @code{_exit},\n"
552 "if any, otherwise @code{#f}.")
1bbd0b84 553#define FUNC_NAME s_scm_status_exit_val
67ec3667 554{
e67dc2be
JB
555 int lstatus;
556
e67dc2be 557 /* On Ultrix, the WIF... macros assume their argument is an lvalue;
e11e83f3 558 go figure. */
a55c2b68 559 lstatus = scm_to_int (status);
e67dc2be 560 if (WIFEXITED (lstatus))
a55c2b68 561 return (scm_from_int (WEXITSTATUS (lstatus)));
67ec3667
GH
562 else
563 return SCM_BOOL_F;
564}
1bbd0b84 565#undef FUNC_NAME
e67dc2be 566
a1ec6916 567SCM_DEFINE (scm_status_term_sig, "status:term-sig", 1, 0, 0,
1bbd0b84 568 (SCM status),
1e6808ea
MG
569 "Return the signal number which terminated the process, if any,\n"
570 "otherwise @code{#f}.")
1bbd0b84 571#define FUNC_NAME s_scm_status_term_sig
67ec3667 572{
e67dc2be
JB
573 int lstatus;
574
a55c2b68 575 lstatus = scm_to_int (status);
e67dc2be 576 if (WIFSIGNALED (lstatus))
a55c2b68 577 return scm_from_int (WTERMSIG (lstatus));
67ec3667
GH
578 else
579 return SCM_BOOL_F;
580}
1bbd0b84 581#undef FUNC_NAME
0f2d19dd 582
a1ec6916 583SCM_DEFINE (scm_status_stop_sig, "status:stop-sig", 1, 0, 0,
1bbd0b84 584 (SCM status),
1e6808ea
MG
585 "Return the signal number which stopped the process, if any,\n"
586 "otherwise @code{#f}.")
1bbd0b84 587#define FUNC_NAME s_scm_status_stop_sig
67ec3667 588{
e67dc2be
JB
589 int lstatus;
590
a55c2b68 591 lstatus = scm_to_int (status);
e67dc2be 592 if (WIFSTOPPED (lstatus))
a55c2b68 593 return scm_from_int (WSTOPSIG (lstatus));
67ec3667
GH
594 else
595 return SCM_BOOL_F;
596}
1bbd0b84 597#undef FUNC_NAME
82893676 598#endif /* __MINGW32__ */
0f2d19dd 599
82893676 600#ifdef HAVE_GETPPID
a1ec6916 601SCM_DEFINE (scm_getppid, "getppid", 0, 0, 0,
1bbd0b84 602 (),
1e6808ea
MG
603 "Return an integer representing the process ID of the parent\n"
604 "process.")
1bbd0b84 605#define FUNC_NAME s_scm_getppid
0f2d19dd 606{
e11e83f3 607 return scm_from_int (getppid ());
0f2d19dd 608}
1bbd0b84 609#undef FUNC_NAME
82893676 610#endif /* HAVE_GETPPID */
0f2d19dd
JB
611
612
82893676 613#ifndef __MINGW32__
a1ec6916 614SCM_DEFINE (scm_getuid, "getuid", 0, 0, 0,
1bbd0b84 615 (),
1e6808ea 616 "Return an integer representing the current real user ID.")
1bbd0b84 617#define FUNC_NAME s_scm_getuid
0f2d19dd 618{
e11e83f3 619 return scm_from_int (getuid ());
0f2d19dd 620}
1bbd0b84 621#undef FUNC_NAME
0f2d19dd
JB
622
623
624
a1ec6916 625SCM_DEFINE (scm_getgid, "getgid", 0, 0, 0,
1bbd0b84 626 (),
1e6808ea 627 "Return an integer representing the current real group ID.")
1bbd0b84 628#define FUNC_NAME s_scm_getgid
0f2d19dd 629{
e11e83f3 630 return scm_from_int (getgid ());
0f2d19dd 631}
1bbd0b84 632#undef FUNC_NAME
0f2d19dd
JB
633
634
635
a1ec6916 636SCM_DEFINE (scm_geteuid, "geteuid", 0, 0, 0,
1bbd0b84 637 (),
1e6808ea 638 "Return an integer representing the current effective user ID.\n"
b380b885 639 "If the system does not support effective IDs, then the real ID\n"
480fa28d 640 "is returned. @code{(provided? 'EIDs)} reports whether the\n"
1e6808ea 641 "system supports effective IDs.")
1bbd0b84 642#define FUNC_NAME s_scm_geteuid
0f2d19dd
JB
643{
644#ifdef HAVE_GETEUID
e11e83f3 645 return scm_from_int (geteuid ());
0f2d19dd 646#else
e11e83f3 647 return scm_from_int (getuid ());
0f2d19dd
JB
648#endif
649}
1bbd0b84 650#undef FUNC_NAME
0f2d19dd
JB
651
652
a1ec6916 653SCM_DEFINE (scm_getegid, "getegid", 0, 0, 0,
1bbd0b84 654 (),
1e6808ea 655 "Return an integer representing the current effective group ID.\n"
b380b885 656 "If the system does not support effective IDs, then the real ID\n"
480fa28d 657 "is returned. @code{(provided? 'EIDs)} reports whether the\n"
1e6808ea 658 "system supports effective IDs.")
1bbd0b84 659#define FUNC_NAME s_scm_getegid
0f2d19dd
JB
660{
661#ifdef HAVE_GETEUID
e11e83f3 662 return scm_from_int (getegid ());
0f2d19dd 663#else
e11e83f3 664 return scm_from_int (getgid ());
0f2d19dd
JB
665#endif
666}
1bbd0b84 667#undef FUNC_NAME
0f2d19dd
JB
668
669
a1ec6916 670SCM_DEFINE (scm_setuid, "setuid", 1, 0, 0,
1bbd0b84 671 (SCM id),
b380b885
MD
672 "Sets both the real and effective user IDs to the integer @var{id}, provided\n"
673 "the process has appropriate privileges.\n"
674 "The return value is unspecified.")
1bbd0b84 675#define FUNC_NAME s_scm_setuid
0f2d19dd 676{
a55c2b68 677 if (setuid (scm_to_int (id)) != 0)
1bbd0b84 678 SCM_SYSERROR;
02b754d3 679 return SCM_UNSPECIFIED;
0f2d19dd 680}
1bbd0b84 681#undef FUNC_NAME
0f2d19dd 682
a1ec6916 683SCM_DEFINE (scm_setgid, "setgid", 1, 0, 0,
1bbd0b84 684 (SCM id),
b380b885
MD
685 "Sets both the real and effective group IDs to the integer @var{id}, provided\n"
686 "the process has appropriate privileges.\n"
687 "The return value is unspecified.")
1bbd0b84 688#define FUNC_NAME s_scm_setgid
0f2d19dd 689{
a55c2b68 690 if (setgid (scm_to_int (id)) != 0)
1bbd0b84 691 SCM_SYSERROR;
02b754d3 692 return SCM_UNSPECIFIED;
0f2d19dd 693}
1bbd0b84 694#undef FUNC_NAME
0f2d19dd 695
a1ec6916 696SCM_DEFINE (scm_seteuid, "seteuid", 1, 0, 0,
1bbd0b84 697 (SCM id),
b380b885
MD
698 "Sets the effective user ID to the integer @var{id}, provided the process\n"
699 "has appropriate privileges. If effective IDs are not supported, the\n"
480fa28d 700 "real ID is set instead -- @code{(provided? 'EIDs)} reports whether the\n"
b380b885
MD
701 "system supports effective IDs.\n"
702 "The return value is unspecified.")
1bbd0b84 703#define FUNC_NAME s_scm_seteuid
0f2d19dd 704{
02b754d3
GH
705 int rv;
706
0f2d19dd 707#ifdef HAVE_SETEUID
a55c2b68 708 rv = seteuid (scm_to_int (id));
0f2d19dd 709#else
a55c2b68 710 rv = setuid (scm_to_int (id));
0f2d19dd 711#endif
02b754d3 712 if (rv != 0)
1bbd0b84 713 SCM_SYSERROR;
02b754d3 714 return SCM_UNSPECIFIED;
0f2d19dd 715}
1bbd0b84 716#undef FUNC_NAME
7beabedb
MG
717#endif /* __MINGW32__ */
718
0f2d19dd 719
0e958795 720#ifdef HAVE_SETEGID
a1ec6916 721SCM_DEFINE (scm_setegid, "setegid", 1, 0, 0,
1bbd0b84 722 (SCM id),
b380b885
MD
723 "Sets the effective group ID to the integer @var{id}, provided the process\n"
724 "has appropriate privileges. If effective IDs are not supported, the\n"
480fa28d 725 "real ID is set instead -- @code{(provided? 'EIDs)} reports whether the\n"
b380b885
MD
726 "system supports effective IDs.\n"
727 "The return value is unspecified.")
1bbd0b84 728#define FUNC_NAME s_scm_setegid
0f2d19dd 729{
02b754d3
GH
730 int rv;
731
0f2d19dd 732#ifdef HAVE_SETEUID
a55c2b68 733 rv = setegid (scm_to_int (id));
0f2d19dd 734#else
a55c2b68 735 rv = setgid (scm_to_int (id));
0f2d19dd 736#endif
02b754d3 737 if (rv != 0)
1bbd0b84 738 SCM_SYSERROR;
02b754d3
GH
739 return SCM_UNSPECIFIED;
740
0f2d19dd 741}
1bbd0b84 742#undef FUNC_NAME
0e958795 743#endif
0f2d19dd 744
82893676
MG
745
746#ifdef HAVE_GETPGRP
a1ec6916 747SCM_DEFINE (scm_getpgrp, "getpgrp", 0, 0, 0,
1bbd0b84 748 (),
1e6808ea 749 "Return an integer representing the current process group ID.\n"
b380b885 750 "This is the POSIX definition, not BSD.")
1bbd0b84 751#define FUNC_NAME s_scm_getpgrp
0f2d19dd
JB
752{
753 int (*fn)();
4625e44f 754 fn = (int (*) ()) getpgrp;
e11e83f3 755 return scm_from_int (fn (0));
0f2d19dd 756}
1bbd0b84 757#undef FUNC_NAME
82893676
MG
758#endif /* HAVE_GETPGRP */
759
0f2d19dd 760
f25f761d 761#ifdef HAVE_SETPGID
a1ec6916 762SCM_DEFINE (scm_setpgid, "setpgid", 2, 0, 0,
1bbd0b84 763 (SCM pid, SCM pgid),
b380b885
MD
764 "Move the process @var{pid} into the process group @var{pgid}. @var{pid} or\n"
765 "@var{pgid} must be integers: they can be zero to indicate the ID of the\n"
766 "current process.\n"
767 "Fails on systems that do not support job control.\n"
768 "The return value is unspecified.")
1bbd0b84 769#define FUNC_NAME s_scm_setpgid
0f2d19dd 770{
02b754d3 771 /* FIXME(?): may be known as setpgrp. */
a55c2b68 772 if (setpgid (scm_to_int (pid), scm_to_int (pgid)) != 0)
1bbd0b84 773 SCM_SYSERROR;
02b754d3 774 return SCM_UNSPECIFIED;
0f2d19dd 775}
1bbd0b84 776#undef FUNC_NAME
f25f761d 777#endif /* HAVE_SETPGID */
0f2d19dd 778
f25f761d 779#ifdef HAVE_SETSID
a1ec6916 780SCM_DEFINE (scm_setsid, "setsid", 0, 0, 0,
1bbd0b84 781 (),
b380b885
MD
782 "Creates a new session. The current process becomes the session leader\n"
783 "and is put in a new process group. The process will be detached\n"
784 "from its controlling terminal if it has one.\n"
785 "The return value is an integer representing the new process group ID.")
1bbd0b84 786#define FUNC_NAME s_scm_setsid
0f2d19dd
JB
787{
788 pid_t sid = setsid ();
02b754d3 789 if (sid == -1)
1bbd0b84 790 SCM_SYSERROR;
02b754d3 791 return SCM_UNSPECIFIED;
0f2d19dd 792}
1bbd0b84 793#undef FUNC_NAME
f25f761d 794#endif /* HAVE_SETSID */
0f2d19dd 795
e8a59063
KR
796
797/* ttyname returns its result in a single static buffer, hence
798 scm_i_misc_mutex for thread safety. In glibc 2.3.2 two threads
799 continuously calling ttyname will otherwise get an overwrite quite
800 easily.
801
802 ttyname_r (when available) could be used instead of scm_i_misc_mutex, but
803 there's probably little to be gained in either speed or parallelism. */
804
82893676 805#ifdef HAVE_TTYNAME
a1ec6916 806SCM_DEFINE (scm_ttyname, "ttyname", 1, 0, 0,
1bbd0b84 807 (SCM port),
1e6808ea
MG
808 "Return a string with the name of the serial terminal device\n"
809 "underlying @var{port}.")
1bbd0b84 810#define FUNC_NAME s_scm_ttyname
0f2d19dd 811{
1d1559ce 812 char *result;
e8a59063
KR
813 int fd, err;
814 SCM ret;
78446828
MV
815
816 port = SCM_COERCE_OUTPORT (port);
34d19ef6 817 SCM_VALIDATE_OPPORT (1, port);
a98bddfd 818 if (!SCM_FPORTP (port))
0f2d19dd 819 return SCM_BOOL_F;
ee149d03 820 fd = SCM_FPORT_FDES (port);
e8a59063
KR
821
822 scm_mutex_lock (&scm_i_misc_mutex);
1d1559ce 823 SCM_SYSCALL (result = ttyname (fd));
e8a59063 824 err = errno;
cc95e00a 825 ret = scm_from_locale_string (result);
e8a59063
KR
826 scm_mutex_unlock (&scm_i_misc_mutex);
827
1d1559ce 828 if (!result)
e8a59063
KR
829 {
830 errno = err;
831 SCM_SYSERROR;
832 }
833 return ret;
0f2d19dd 834}
1bbd0b84 835#undef FUNC_NAME
82893676 836#endif /* HAVE_TTYNAME */
0f2d19dd 837
e8a59063 838
0a9d83b0
KR
839/* For thread safety "buf" is used instead of NULL for the ctermid static
840 buffer. Actually it's unlikely the controlling terminal will change
841 during program execution, and indeed on glibc (2.3.2) it's always just
842 "/dev/tty", but L_ctermid on the stack is easy and fast and guarantees
843 safety everywhere. */
f25f761d 844#ifdef HAVE_CTERMID
a1ec6916 845SCM_DEFINE (scm_ctermid, "ctermid", 0, 0, 0,
1bbd0b84 846 (),
1e6808ea
MG
847 "Return a string containing the file name of the controlling\n"
848 "terminal for the current process.")
1bbd0b84 849#define FUNC_NAME s_scm_ctermid
0f2d19dd 850{
0a9d83b0
KR
851 char buf[L_ctermid];
852 char *result = ctermid (buf);
02b754d3 853 if (*result == '\0')
1bbd0b84 854 SCM_SYSERROR;
cc95e00a 855 return scm_from_locale_string (result);
0f2d19dd 856}
1bbd0b84 857#undef FUNC_NAME
f25f761d 858#endif /* HAVE_CTERMID */
0f2d19dd 859
f25f761d 860#ifdef HAVE_TCGETPGRP
a1ec6916 861SCM_DEFINE (scm_tcgetpgrp, "tcgetpgrp", 1, 0, 0,
1bbd0b84 862 (SCM port),
1e6808ea
MG
863 "Return the process group ID of the foreground process group\n"
864 "associated with the terminal open on the file descriptor\n"
865 "underlying @var{port}.\n"
866 "\n"
b380b885
MD
867 "If there is no foreground process group, the return value is a\n"
868 "number greater than 1 that does not match the process group ID\n"
869 "of any existing process group. This can happen if all of the\n"
870 "processes in the job that was formerly the foreground job have\n"
871 "terminated, and no other job has yet been moved into the\n"
872 "foreground.")
1bbd0b84 873#define FUNC_NAME s_scm_tcgetpgrp
0f2d19dd
JB
874{
875 int fd;
876 pid_t pgid;
78446828
MV
877
878 port = SCM_COERCE_OUTPORT (port);
879
34d19ef6 880 SCM_VALIDATE_OPFPORT (1, port);
ee149d03
JB
881 fd = SCM_FPORT_FDES (port);
882 if ((pgid = tcgetpgrp (fd)) == -1)
1bbd0b84 883 SCM_SYSERROR;
e11e83f3 884 return scm_from_int (pgid);
1bbd0b84
GB
885}
886#undef FUNC_NAME
f25f761d 887#endif /* HAVE_TCGETPGRP */
0f2d19dd 888
f25f761d 889#ifdef HAVE_TCSETPGRP
a1ec6916 890SCM_DEFINE (scm_tcsetpgrp, "tcsetpgrp", 2, 0, 0,
1bbd0b84 891 (SCM port, SCM pgid),
b380b885
MD
892 "Set the foreground process group ID for the terminal used by the file\n"
893 "descriptor underlying @var{port} to the integer @var{pgid}.\n"
894 "The calling process\n"
895 "must be a member of the same session as @var{pgid} and must have the same\n"
896 "controlling terminal. The return value is unspecified.")
1bbd0b84 897#define FUNC_NAME s_scm_tcsetpgrp
0f2d19dd
JB
898{
899 int fd;
78446828
MV
900
901 port = SCM_COERCE_OUTPORT (port);
902
34d19ef6 903 SCM_VALIDATE_OPFPORT (1, port);
ee149d03 904 fd = SCM_FPORT_FDES (port);
a55c2b68 905 if (tcsetpgrp (fd, scm_to_int (pgid)) == -1)
1bbd0b84 906 SCM_SYSERROR;
02b754d3 907 return SCM_UNSPECIFIED;
1bbd0b84
GB
908}
909#undef FUNC_NAME
f25f761d 910#endif /* HAVE_TCSETPGRP */
0f2d19dd 911
7f03f970
MV
912static void
913free_string_pointers (void *data)
0f2d19dd 914{
7f03f970 915 scm_i_free_string_pointers ((char **)data);
0f2d19dd
JB
916}
917
a1ec6916 918SCM_DEFINE (scm_execl, "execl", 1, 0, 1,
1bbd0b84 919 (SCM filename, SCM args),
b380b885
MD
920 "Executes the file named by @var{path} as a new process image.\n"
921 "The remaining arguments are supplied to the process; from a C program\n"
bb2c02f2 922 "they are accessible as the @code{argv} argument to @code{main}.\n"
b380b885 923 "Conventionally the first @var{arg} is the same as @var{path}.\n"
8f85c0c6 924 "All arguments must be strings.\n\n"
b380b885
MD
925 "If @var{arg} is missing, @var{path} is executed with a null\n"
926 "argument list, which may have system-dependent side-effects.\n\n"
927 "This procedure is currently implemented using the @code{execv} system\n"
928 "call, but we call it @code{execl} because of its Scheme calling interface.")
1bbd0b84 929#define FUNC_NAME s_scm_execl
0f2d19dd 930{
7f03f970
MV
931 char *exec_file;
932 char **exec_argv;
933
934 scm_frame_begin (0);
935
936 exec_file = scm_to_locale_string (filename);
937 scm_frame_free (exec_file);
938
939 exec_argv = scm_i_allocate_string_pointers (args);
940 scm_frame_unwind_handler (free_string_pointers, exec_argv,
941 SCM_F_WIND_EXPLICITLY);
942
943 execv (exec_file, exec_argv);
1bbd0b84 944 SCM_SYSERROR;
7f03f970 945
02b754d3 946 /* not reached. */
7f03f970 947 scm_frame_end ();
02b754d3 948 return SCM_BOOL_F;
0f2d19dd 949}
1bbd0b84 950#undef FUNC_NAME
0f2d19dd 951
a1ec6916 952SCM_DEFINE (scm_execlp, "execlp", 1, 0, 1,
1bbd0b84 953 (SCM filename, SCM args),
b380b885
MD
954 "Similar to @code{execl}, however if\n"
955 "@var{filename} does not contain a slash\n"
956 "then the file to execute will be located by searching the\n"
957 "directories listed in the @code{PATH} environment variable.\n\n"
6bcd01fc 958 "This procedure is currently implemented using the @code{execvp} system\n"
b380b885 959 "call, but we call it @code{execlp} because of its Scheme calling interface.")
1bbd0b84 960#define FUNC_NAME s_scm_execlp
0f2d19dd 961{
7f03f970
MV
962 char *exec_file;
963 char **exec_argv;
964
965 scm_frame_begin (0);
966
967 exec_file = scm_to_locale_string (filename);
968 scm_frame_free (exec_file);
969
970 exec_argv = scm_i_allocate_string_pointers (args);
971 scm_frame_unwind_handler (free_string_pointers, exec_argv,
972 SCM_F_WIND_EXPLICITLY);
973
974 execvp (exec_file, exec_argv);
1bbd0b84 975 SCM_SYSERROR;
7f03f970 976
02b754d3 977 /* not reached. */
7f03f970 978 scm_frame_end ();
02b754d3 979 return SCM_BOOL_F;
0f2d19dd 980}
1bbd0b84 981#undef FUNC_NAME
0f2d19dd 982
6afcd3b2 983
807f353f
KR
984/* OPTIMIZE-ME: scm_execle doesn't need malloced copies of the environment
985 list strings the way environ_list_to_c gives. */
986
a1ec6916 987SCM_DEFINE (scm_execle, "execle", 2, 0, 1,
1bbd0b84 988 (SCM filename, SCM env, SCM args),
b380b885
MD
989 "Similar to @code{execl}, but the environment of the new process is\n"
990 "specified by @var{env}, which must be a list of strings as returned by the\n"
991 "@code{environ} procedure.\n\n"
992 "This procedure is currently implemented using the @code{execve} system\n"
993 "call, but we call it @code{execle} because of its Scheme calling interface.")
1bbd0b84 994#define FUNC_NAME s_scm_execle
6afcd3b2 995{
7f03f970 996 char **exec_argv;
6afcd3b2 997 char **exec_env;
7f03f970 998 char *exec_file;
6afcd3b2 999
7f03f970
MV
1000 scm_frame_begin (0);
1001
1002 exec_file = scm_to_locale_string (filename);
1003 scm_frame_free (exec_file);
1004
1005 exec_argv = scm_i_allocate_string_pointers (args);
1006 scm_frame_unwind_handler (free_string_pointers, exec_argv,
1007 SCM_F_WIND_EXPLICITLY);
1008
1009 exec_env = scm_i_allocate_string_pointers (env);
1010 scm_frame_unwind_handler (free_string_pointers, exec_env,
1011 SCM_F_WIND_EXPLICITLY);
1012
1013 execve (exec_file, exec_argv, exec_env);
1bbd0b84 1014 SCM_SYSERROR;
7f03f970 1015
6afcd3b2 1016 /* not reached. */
7f03f970 1017 scm_frame_end ();
6afcd3b2
GH
1018 return SCM_BOOL_F;
1019}
1bbd0b84 1020#undef FUNC_NAME
6afcd3b2 1021
82893676 1022#ifdef HAVE_FORK
a1ec6916 1023SCM_DEFINE (scm_fork, "primitive-fork", 0, 0, 0,
1bbd0b84 1024 (),
b380b885
MD
1025 "Creates a new \"child\" process by duplicating the current \"parent\" process.\n"
1026 "In the child the return value is 0. In the parent the return value is\n"
1027 "the integer process ID of the child.\n\n"
1028 "This procedure has been renamed from @code{fork} to avoid a naming conflict\n"
1029 "with the scsh fork.")
1bbd0b84 1030#define FUNC_NAME s_scm_fork
0f2d19dd 1031{
bab0f4e5 1032 int pid;
0f2d19dd
JB
1033 pid = fork ();
1034 if (pid == -1)
1bbd0b84 1035 SCM_SYSERROR;
e11e83f3 1036 return scm_from_int (pid);
0f2d19dd 1037}
1bbd0b84 1038#undef FUNC_NAME
82893676 1039#endif /* HAVE_FORK */
0f2d19dd 1040
4f68365d
MV
1041#ifdef __MINGW32__
1042# include "win32-uname.h"
1043#endif
1044
1045#if defined (HAVE_UNAME) || defined (__MINGW32__)
a1ec6916 1046SCM_DEFINE (scm_uname, "uname", 0, 0, 0,
1bbd0b84 1047 (),
1e6808ea
MG
1048 "Return an object with some information about the computer\n"
1049 "system the program is running on.")
1bbd0b84 1050#define FUNC_NAME s_scm_uname
0f2d19dd 1051{
0f2d19dd 1052 struct utsname buf;
1d1559ce 1053 SCM result = scm_c_make_vector (5, SCM_UNSPECIFIED);
e1a191a8 1054 if (uname (&buf) < 0)
1bbd0b84 1055 SCM_SYSERROR;
cc95e00a
MV
1056 SCM_VECTOR_SET(result, 0, scm_from_locale_string (buf.sysname));
1057 SCM_VECTOR_SET(result, 1, scm_from_locale_string (buf.nodename));
1058 SCM_VECTOR_SET(result, 2, scm_from_locale_string (buf.release));
1059 SCM_VECTOR_SET(result, 3, scm_from_locale_string (buf.version));
1060 SCM_VECTOR_SET(result, 4, scm_from_locale_string (buf.machine));
0f2d19dd 1061/*
02b754d3 1062 a linux special?
cc95e00a 1063 SCM_VECTOR_SET(result, 5, scm_from_locale_string (buf.domainname));
0f2d19dd 1064*/
1d1559ce 1065 return result;
0f2d19dd 1066}
1bbd0b84 1067#undef FUNC_NAME
f25f761d 1068#endif /* HAVE_UNAME */
0f2d19dd 1069
a1ec6916 1070SCM_DEFINE (scm_environ, "environ", 0, 1, 0,
1bbd0b84 1071 (SCM env),
1e6808ea
MG
1072 "If @var{env} is omitted, return the current environment (in the\n"
1073 "Unix sense) as a list of strings. Otherwise set the current\n"
1074 "environment, which is also the default environment for child\n"
1075 "processes, to the supplied list of strings. Each member of\n"
1076 "@var{env} should be of the form @code{NAME=VALUE} and values of\n"
1077 "@code{NAME} should not be duplicated. If @var{env} is supplied\n"
1078 "then the return value is unspecified.")
1bbd0b84 1079#define FUNC_NAME s_scm_environ
0f2d19dd
JB
1080{
1081 if (SCM_UNBNDP (env))
1082 return scm_makfromstrs (-1, environ);
1083 else
1084 {
0f2d19dd 1085 char **new_environ;
6afcd3b2 1086
7f03f970 1087 new_environ = scm_i_allocate_string_pointers (env);
0f2d19dd
JB
1088 /* Free the old environment, except when called for the first
1089 * time.
1090 */
1091 {
0f2d19dd
JB
1092 static int first = 1;
1093 if (!first)
7f03f970 1094 scm_i_free_string_pointers (environ);
0f2d19dd
JB
1095 first = 0;
1096 }
1097 environ = new_environ;
1098 return SCM_UNSPECIFIED;
1099 }
1100}
1bbd0b84 1101#undef FUNC_NAME
0f2d19dd 1102
9ee5fce4
MD
1103#ifdef L_tmpnam
1104
a1ec6916 1105SCM_DEFINE (scm_tmpnam, "tmpnam", 0, 0, 0,
1bbd0b84 1106 (),
1e6808ea
MG
1107 "Return a name in the file system that does not match any\n"
1108 "existing file. However there is no guarantee that another\n"
1109 "process will not create the file after @code{tmpnam} is called.\n"
1110 "Care should be taken if opening the file, e.g., use the\n"
1111 "@code{O_EXCL} open flag or use @code{mkstemp!} instead.")
1bbd0b84 1112#define FUNC_NAME s_scm_tmpnam
9ee5fce4
MD
1113{
1114 char name[L_tmpnam];
6d163216
GH
1115 char *rv;
1116
1117 SCM_SYSCALL (rv = tmpnam (name));
1118 if (rv == NULL)
1119 /* not SCM_SYSERROR since errno probably not set. */
1120 SCM_MISC_ERROR ("tmpnam failed", SCM_EOL);
cc95e00a 1121 return scm_from_locale_string (name);
9ee5fce4 1122}
0f981281 1123#undef FUNC_NAME
0f2d19dd 1124
1bbd0b84 1125#endif
1cc91f1b 1126
4f68365d
MV
1127#ifndef HAVE_MKSTEMP
1128extern int mkstemp (char *);
1129#endif
1130
6d163216
GH
1131SCM_DEFINE (scm_mkstemp, "mkstemp!", 1, 0, 0,
1132 (SCM tmpl),
1e6808ea
MG
1133 "Create a new unique file in the file system and returns a new\n"
1134 "buffered port open for reading and writing to the file.\n"
1135 "@var{tmpl} is a string specifying where the file should be\n"
1136 "created: it must end with @code{XXXXXX} and will be changed in\n"
1137 "place to return the name of the temporary file.")
6d163216
GH
1138#define FUNC_NAME s_scm_mkstemp
1139{
1140 char *c_tmpl;
71978ac9 1141 int rv;
6d163216 1142
892065da
MV
1143 scm_frame_begin (0);
1144
1145 c_tmpl = scm_to_locale_string (tmpl);
1146 scm_frame_free (c_tmpl);
1147
6d163216
GH
1148 SCM_SYSCALL (rv = mkstemp (c_tmpl));
1149 if (rv == -1)
1150 SCM_SYSERROR;
892065da
MV
1151
1152 scm_substring_move_x (scm_from_locale_string (c_tmpl),
1153 SCM_INUM0, scm_string_length (tmpl),
1154 tmpl, SCM_INUM0);
1155
1156 scm_frame_end ();
6d163216
GH
1157 return scm_fdes_to_port (rv, "w+", tmpl);
1158}
1159#undef FUNC_NAME
1160
a1ec6916 1161SCM_DEFINE (scm_utime, "utime", 1, 2, 0,
1bbd0b84 1162 (SCM pathname, SCM actime, SCM modtime),
1e6808ea
MG
1163 "@code{utime} sets the access and modification times for the\n"
1164 "file named by @var{path}. If @var{actime} or @var{modtime} is\n"
1165 "not supplied, then the current time is used. @var{actime} and\n"
1166 "@var{modtime} must be integer time values as returned by the\n"
1167 "@code{current-time} procedure.\n"
1168 "@lisp\n"
b380b885 1169 "(utime \"foo\" (- (current-time) 3600))\n"
1e6808ea
MG
1170 "@end lisp\n"
1171 "will set the access time to one hour in the past and the\n"
1172 "modification time to the current time.")
1bbd0b84 1173#define FUNC_NAME s_scm_utime
0f2d19dd
JB
1174{
1175 int rv;
1176 struct utimbuf utm_tmp;
1177
0f2d19dd
JB
1178 if (SCM_UNBNDP (actime))
1179 SCM_SYSCALL (time (&utm_tmp.actime));
1180 else
e4b265d8 1181 utm_tmp.actime = SCM_NUM2ULONG (2, actime);
0f2d19dd
JB
1182
1183 if (SCM_UNBNDP (modtime))
1184 SCM_SYSCALL (time (&utm_tmp.modtime));
1185 else
e4b265d8 1186 utm_tmp.modtime = SCM_NUM2ULONG (3, modtime);
0f2d19dd 1187
f015614a
MV
1188 STRING_SYSCALL (pathname, c_pathname,
1189 rv = utime (c_pathname, &utm_tmp));
02b754d3 1190 if (rv != 0)
1bbd0b84 1191 SCM_SYSERROR;
02b754d3 1192 return SCM_UNSPECIFIED;
0f2d19dd 1193}
1bbd0b84 1194#undef FUNC_NAME
0f2d19dd 1195
a1ec6916 1196SCM_DEFINE (scm_access, "access?", 2, 0, 0,
1bbd0b84 1197 (SCM path, SCM how),
20e0b166
KR
1198 "Test accessibility of a file under the real UID and GID of the\n"
1199 "calling process. The return is @code{#t} if @var{path} exists\n"
1200 "and the permissions requested by @var{how} are all allowed, or\n"
1201 "@code{#f} if not.\n"
1e6808ea 1202 "\n"
20e0b166
KR
1203 "@var{how} is an integer which is one of the following values,\n"
1204 "or a bitwise-OR (@code{logior}) of multiple values.\n"
1e6808ea 1205 "\n"
b380b885 1206 "@defvar R_OK\n"
20e0b166 1207 "Test for read permission.\n"
b380b885
MD
1208 "@end defvar\n"
1209 "@defvar W_OK\n"
20e0b166 1210 "Test for write permission.\n"
b380b885
MD
1211 "@end defvar\n"
1212 "@defvar X_OK\n"
20e0b166 1213 "Test for execute permission.\n"
b380b885
MD
1214 "@end defvar\n"
1215 "@defvar F_OK\n"
20e0b166
KR
1216 "Test for existence of the file. This is implied by each of the\n"
1217 "other tests, so there's no need to combine it with them.\n"
1218 "@end defvar\n"
1219 "\n"
1220 "It's important to note that @code{access?} does not simply\n"
1221 "indicate what will happen on attempting to read or write a\n"
1222 "file. In normal circumstances it does, but in a set-UID or\n"
1223 "set-GID program it doesn't because @code{access?} tests the\n"
1224 "real ID, whereas an open or execute attempt uses the effective\n"
1225 "ID.\n"
1226 "\n"
1227 "A program which will never run set-UID/GID can ignore the\n"
1228 "difference between real and effective IDs, but for maximum\n"
1229 "generality, especially in library functions, it's best not to\n"
1230 "use @code{access?} to predict the result of an open or execute,\n"
1231 "instead simply attempt that and catch any exception.\n"
1232 "\n"
1233 "The main use for @code{access?} is to let a set-UID/GID program\n"
1234 "determine what the invoking user would have been allowed to do,\n"
1235 "without the greater (or perhaps lesser) privileges afforded by\n"
1236 "the effective ID. For more on this, see ``Testing File\n"
1237 "Access'' in The GNU C Library Reference Manual.")
1bbd0b84 1238#define FUNC_NAME s_scm_access
0f2d19dd
JB
1239{
1240 int rv;
1241
f015614a
MV
1242 WITH_STRING (path, c_path,
1243 rv = access (c_path, scm_to_int (how)));
7888309b 1244 return scm_from_bool (!rv);
0f2d19dd 1245}
1bbd0b84 1246#undef FUNC_NAME
0f2d19dd 1247
a1ec6916 1248SCM_DEFINE (scm_getpid, "getpid", 0, 0, 0,
1bbd0b84 1249 (),
1e6808ea 1250 "Return an integer representing the current process ID.")
1bbd0b84 1251#define FUNC_NAME s_scm_getpid
0f2d19dd 1252{
e11e83f3 1253 return scm_from_ulong (getpid ());
0f2d19dd 1254}
1bbd0b84 1255#undef FUNC_NAME
0f2d19dd 1256
a1ec6916 1257SCM_DEFINE (scm_putenv, "putenv", 1, 0, 0,
1bbd0b84 1258 (SCM str),
b380b885
MD
1259 "Modifies the environment of the current process, which is\n"
1260 "also the default environment inherited by child processes.\n\n"
1261 "If @var{string} is of the form @code{NAME=VALUE} then it will be written\n"
1262 "directly into the environment, replacing any existing environment string\n"
1263 "with\n"
1264 "name matching @code{NAME}. If @var{string} does not contain an equal\n"
1265 "sign, then any existing string with name matching @var{string} will\n"
1266 "be removed.\n\n"
1267 "The return value is unspecified.")
1bbd0b84 1268#define FUNC_NAME s_scm_putenv
0f2d19dd 1269{
f158788f 1270 int rv;
f015614a
MV
1271 char *c_str = scm_to_locale_string (str);
1272#ifdef __MINGW32__
1273 size_t len = strlen (c_str);
1274#endif
002409fe 1275
f015614a 1276 if (strchr (c_str, '=') == NULL)
002409fe 1277 {
1e498fbd 1278#ifdef HAVE_UNSETENV
002409fe 1279 /* No '=' in argument means we should remove the variable from
ff4b8391
KR
1280 the environment. Not all putenvs understand this (for instance
1281 FreeBSD 4.8 doesn't). To be safe, we do it explicitely using
1282 unsetenv. */
f015614a
MV
1283 unsetenv (c_str);
1284 free (c_str);
1e498fbd
SJ
1285#else
1286 /* On e.g. Win32 hosts putenv() called with 'name=' removes the
1287 environment variable 'name'. */
f158788f 1288 int e;
edea856c 1289 char *ptr = scm_malloc (len + 2);
f015614a
MV
1290 strcpy (ptr, c_str);
1291 strcpy (ptr+len, "=");
1e498fbd 1292 rv = putenv (ptr);
f015614a 1293 e = errno; free (ptr); free (c_str); errno = e;
1e498fbd
SJ
1294 if (rv < 0)
1295 SCM_SYSERROR;
fcc5d734 1296#endif /* !HAVE_UNSETENV */
002409fe
MV
1297 }
1298 else
1299 {
fcc5d734
SJ
1300#ifdef __MINGW32__
1301 /* If str is "FOO=", ie. attempting to set an empty string, then
1302 we need to see if it's been successful. On MINGW, "FOO="
1303 means remove FOO from the environment. As a workaround, we
1304 set "FOO= ", ie. a space, and then modify the string returned
1305 by getenv. It's not enough just to modify the string we set,
1306 because MINGW putenv copies it. */
f015614a
MV
1307
1308 if (c_str[len-1] == '=')
fcc5d734 1309 {
f015614a
MV
1310 char *ptr = scm_malloc (len+2);
1311 strcpy (ptr, c_str);
1312 strcpy (ptr+len, " ");
1313 rv = putenv (ptr);
1314 if (rv < 0)
1315 {
1316 int eno = errno;
1317 free (c_str);
1318 errno = eno;
1319 SCM_SYSERROR;
fcc5d734 1320 }
f015614a
MV
1321 /* truncate to just the name */
1322 c_str[len-1] = '\0';
1323 ptr = getenv (c_str);
1324 if (ptr)
1325 ptr[0] = '\0';
fcc5d734
SJ
1326 return SCM_UNSPECIFIED;
1327 }
1328#endif /* __MINGW32__ */
1329
f015614a
MV
1330 /* Leave c_str in the environment. */
1331
1332 rv = putenv (c_str);
002409fe
MV
1333 if (rv < 0)
1334 SCM_SYSERROR;
1335 }
f93ddd39 1336 return SCM_UNSPECIFIED;
0f2d19dd 1337}
1bbd0b84 1338#undef FUNC_NAME
0f2d19dd 1339
f25f761d 1340#ifdef HAVE_SETLOCALE
a1ec6916 1341SCM_DEFINE (scm_setlocale, "setlocale", 1, 1, 0,
1bbd0b84 1342 (SCM category, SCM locale),
1e6808ea
MG
1343 "If @var{locale} is omitted, return the current value of the\n"
1344 "specified locale category as a system-dependent string.\n"
1345 "@var{category} should be specified using the values\n"
1346 "@code{LC_COLLATE}, @code{LC_ALL} etc.\n"
1347 "\n"
1348 "Otherwise the specified locale category is set to the string\n"
1349 "@var{locale} and the new value is returned as a\n"
1350 "system-dependent string. If @var{locale} is an empty string,\n"
bb2c02f2 1351 "the locale will be set using environment variables.")
1bbd0b84 1352#define FUNC_NAME s_scm_setlocale
0f2d19dd 1353{
0f2d19dd
JB
1354 char *clocale;
1355 char *rv;
1356
f015614a
MV
1357 scm_frame_begin (0);
1358
0f2d19dd
JB
1359 if (SCM_UNBNDP (locale))
1360 {
1361 clocale = NULL;
1362 }
1363 else
1364 {
f015614a
MV
1365 clocale = scm_to_locale_string (locale);
1366 scm_frame_free (clocale);
0f2d19dd
JB
1367 }
1368
9361f762 1369 rv = setlocale (scm_i_to_lc_category (category, 1), clocale);
02b754d3 1370 if (rv == NULL)
1bbd0b84 1371 SCM_SYSERROR;
f015614a
MV
1372
1373 scm_frame_end ();
1374 return scm_from_locale_string (rv);
0f2d19dd 1375}
1bbd0b84 1376#undef FUNC_NAME
f25f761d 1377#endif /* HAVE_SETLOCALE */
0f2d19dd 1378
f25f761d 1379#ifdef HAVE_MKNOD
a1ec6916 1380SCM_DEFINE (scm_mknod, "mknod", 4, 0, 0,
1bbd0b84 1381 (SCM path, SCM type, SCM perms, SCM dev),
b380b885
MD
1382 "Creates a new special file, such as a file corresponding to a device.\n"
1383 "@var{path} specifies the name of the file. @var{type} should\n"
1384 "be one of the following symbols:\n"
1385 "regular, directory, symlink, block-special, char-special,\n"
1386 "fifo, or socket. @var{perms} (an integer) specifies the file permissions.\n"
1387 "@var{dev} (an integer) specifies which device the special file refers\n"
1388 "to. Its exact interpretation depends on the kind of special file\n"
1389 "being created.\n\n"
1390 "E.g.,\n"
1e6808ea 1391 "@lisp\n"
09831f94 1392 "(mknod \"/dev/fd0\" 'block-special #o660 (+ (* 2 256) 2))\n"
1e6808ea 1393 "@end lisp\n\n"
a3c8b9fc 1394 "The return value is unspecified.")
1bbd0b84 1395#define FUNC_NAME s_scm_mknod
0f2d19dd 1396{
0f2d19dd 1397 int val;
cc95e00a 1398 const char *p;
82a76bdf 1399 int ctype = 0;
19468eff 1400
a6d9e5ab 1401 SCM_VALIDATE_STRING (1, path);
34d19ef6 1402 SCM_VALIDATE_SYMBOL (2, type);
19468eff 1403
cc95e00a 1404 p = scm_i_symbol_chars (type);
19468eff
GH
1405 if (strcmp (p, "regular") == 0)
1406 ctype = S_IFREG;
1407 else if (strcmp (p, "directory") == 0)
1408 ctype = S_IFDIR;
1409 else if (strcmp (p, "symlink") == 0)
1410 ctype = S_IFLNK;
1411 else if (strcmp (p, "block-special") == 0)
1412 ctype = S_IFBLK;
1413 else if (strcmp (p, "char-special") == 0)
1414 ctype = S_IFCHR;
1415 else if (strcmp (p, "fifo") == 0)
1416 ctype = S_IFIFO;
e655d034 1417#ifdef S_IFSOCK
19468eff
GH
1418 else if (strcmp (p, "socket") == 0)
1419 ctype = S_IFSOCK;
e655d034 1420#endif
19468eff 1421 else
34d19ef6 1422 SCM_OUT_OF_RANGE (2, type);
19468eff 1423
f015614a
MV
1424 STRING_SYSCALL (path, c_path,
1425 val = mknod (c_path,
1426 ctype | scm_to_int (perms),
1427 scm_to_int (dev)));
02b754d3 1428 if (val != 0)
1bbd0b84 1429 SCM_SYSERROR;
02b754d3 1430 return SCM_UNSPECIFIED;
0f2d19dd 1431}
1bbd0b84 1432#undef FUNC_NAME
f25f761d 1433#endif /* HAVE_MKNOD */
0f2d19dd 1434
f25f761d 1435#ifdef HAVE_NICE
a1ec6916 1436SCM_DEFINE (scm_nice, "nice", 1, 0, 0,
1bbd0b84 1437 (SCM incr),
b380b885
MD
1438 "Increment the priority of the current process by @var{incr}. A higher\n"
1439 "priority value means that the process runs less often.\n"
1440 "The return value is unspecified.")
1bbd0b84 1441#define FUNC_NAME s_scm_nice
0f2d19dd 1442{
f1c82f55
KR
1443 /* nice() returns "prio-NZERO" on success or -1 on error, but -1 can arise
1444 from "prio-NZERO", so an error must be detected from errno changed */
1445 errno = 0;
1446 nice (scm_to_int (incr));
1447 if (errno != 0)
1bbd0b84 1448 SCM_SYSERROR;
02b754d3 1449 return SCM_UNSPECIFIED;
0f2d19dd 1450}
1bbd0b84 1451#undef FUNC_NAME
f25f761d 1452#endif /* HAVE_NICE */
0f2d19dd 1453
f25f761d 1454#ifdef HAVE_SYNC
a1ec6916 1455SCM_DEFINE (scm_sync, "sync", 0, 0, 0,
1bbd0b84 1456 (),
b380b885
MD
1457 "Flush the operating system disk buffers.\n"
1458 "The return value is unspecified.")
1bbd0b84 1459#define FUNC_NAME s_scm_sync
0f2d19dd 1460{
0f2d19dd 1461 sync();
127ec750 1462 return SCM_UNSPECIFIED;
0f2d19dd 1463}
1bbd0b84 1464#undef FUNC_NAME
f25f761d 1465#endif /* HAVE_SYNC */
0f2d19dd 1466
33bea692
KR
1467
1468/* crypt() returns a pointer to a static buffer, so we use scm_i_misc_mutex
1469 to avoid another thread overwriting it. A test program running crypt
1470 continuously in two threads can be quickly seen tripping this problem.
1471 crypt() is pretty slow normally, so a mutex shouldn't add much overhead.
1472
1473 glibc has a thread-safe crypt_r, but (in version 2.3.2) it runs a lot
1474 slower (about 5x) than plain crypt if you pass an uninitialized data
1475 block each time. Presumably there's some one-time setups. The best way
1476 to use crypt_r for parallel execution in multiple threads would probably
1477 be to maintain a little pool of initialized crypt_data structures, take
1478 one and use it, then return it to the pool. That pool could be garbage
1479 collected so it didn't add permanently to memory use if only a few crypt
1480 calls are made. But we expect crypt will be used rarely, and even more
1481 rarely will there be any desire for lots of parallel execution on
1482 multiple cpus. So for now we don't bother with anything fancy, just
1483 ensure it works. */
1484
b9a7b725 1485#if HAVE_CRYPT
33bea692 1486SCM_DEFINE (scm_crypt, "crypt", 2, 0, 0,
94e6d793
MG
1487 (SCM key, SCM salt),
1488 "Encrypt @var{key} using @var{salt} as the salt value to the\n"
9401323e 1489 "crypt(3) library call.")
94e6d793
MG
1490#define FUNC_NAME s_scm_crypt
1491{
33bea692 1492 SCM ret;
f015614a 1493 char *c_key, *c_salt;
94e6d793 1494
33bea692
KR
1495 scm_frame_begin (0);
1496 scm_frame_unwind_handler ((void(*)(void*)) scm_mutex_unlock,
1497 &scm_i_misc_mutex,
1498 SCM_F_WIND_EXPLICITLY);
1499 scm_mutex_lock (&scm_i_misc_mutex);
1500
f015614a
MV
1501 c_key = scm_to_locale_string (key);
1502 scm_frame_free (c_key);
1503 c_salt = scm_to_locale_string (salt);
1504 scm_frame_free (c_key);
1505
1506 ret = scm_from_locale_string (crypt (c_key, c_salt));
33bea692
KR
1507
1508 scm_frame_end ();
1509 return ret;
94e6d793
MG
1510}
1511#undef FUNC_NAME
b9a7b725 1512#endif /* HAVE_CRYPT */
94e6d793
MG
1513
1514#if HAVE_CHROOT
1515SCM_DEFINE (scm_chroot, "chroot", 1, 0, 0,
1516 (SCM path),
1517 "Change the root directory to that specified in @var{path}.\n"
1518 "This directory will be used for path names beginning with\n"
1519 "@file{/}. The root directory is inherited by all children\n"
1520 "of the current process. Only the superuser may change the\n"
1521 "root directory.")
1522#define FUNC_NAME s_scm_chroot
1523{
f015614a 1524 int rv;
94e6d793 1525
f015614a
MV
1526 WITH_STRING (path, c_path,
1527 rv = chroot (c_path));
1528 if (rv == -1)
94e6d793
MG
1529 SCM_SYSERROR;
1530 return SCM_UNSPECIFIED;
1531}
1532#undef FUNC_NAME
1533#endif /* HAVE_CHROOT */
1534
7beabedb
MG
1535
1536#ifdef __MINGW32__
1537/* Wrapper function to supplying `getlogin()' under Windows. */
1538static char * getlogin (void)
1539{
1540 static char user[256];
1541 static unsigned long len = 256;
1542
1543 if (!GetUserName (user, &len))
1544 return NULL;
1545 return user;
1546}
1547#endif /* __MINGW32__ */
1548
1549
4f68365d 1550#if defined (HAVE_GETLOGIN) || defined (__MINGW32__)
94e6d793
MG
1551SCM_DEFINE (scm_getlogin, "getlogin", 0, 0, 0,
1552 (void),
1553 "Return a string containing the name of the user logged in on\n"
1554 "the controlling terminal of the process, or @code{#f} if this\n"
1555 "information cannot be obtained.")
1556#define FUNC_NAME s_scm_getlogin
1557{
1558 char * p;
1559
1560 p = getlogin ();
1561 if (!p || !*p)
1562 return SCM_BOOL_F;
cc95e00a 1563 return scm_from_locale_string (p);
94e6d793
MG
1564}
1565#undef FUNC_NAME
1566#endif /* HAVE_GETLOGIN */
1567
1568#if HAVE_CUSERID
1569SCM_DEFINE (scm_cuserid, "cuserid", 0, 0, 0,
1570 (void),
1571 "Return a string containing a user name associated with the\n"
1572 "effective user id of the process. Return @code{#f} if this\n"
1573 "information cannot be obtained.")
1574#define FUNC_NAME s_scm_cuserid
1575{
1b317eb1 1576 char buf[L_cuserid];
94e6d793
MG
1577 char * p;
1578
1b317eb1 1579 p = cuserid (buf);
94e6d793
MG
1580 if (!p || !*p)
1581 return SCM_BOOL_F;
cc95e00a 1582 return scm_from_locale_string (p);
94e6d793
MG
1583}
1584#undef FUNC_NAME
1585#endif /* HAVE_CUSERID */
1586
1587#if HAVE_GETPRIORITY
1588SCM_DEFINE (scm_getpriority, "getpriority", 2, 0, 0,
1589 (SCM which, SCM who),
1590 "Return the scheduling priority of the process, process group\n"
1591 "or user, as indicated by @var{which} and @var{who}. @var{which}\n"
1592 "is one of the variables @code{PRIO_PROCESS}, @code{PRIO_PGRP}\n"
1593 "or @code{PRIO_USER}, and @var{who} is interpreted relative to\n"
1594 "@var{which} (a process identifier for @code{PRIO_PROCESS},\n"
1595 "process group identifier for @code{PRIO_PGRP}, and a user\n"
1596 "identifier for @code{PRIO_USER}. A zero value of @var{who}\n"
1597 "denotes the current process, process group, or user. Return\n"
1598 "the highest priority (lowest numerical value) of any of the\n"
1599 "specified processes.")
1600#define FUNC_NAME s_scm_getpriority
1601{
1602 int cwhich, cwho, ret;
1603
a55c2b68
MV
1604 cwhich = scm_to_int (which);
1605 cwho = scm_to_int (who);
94e6d793
MG
1606
1607 /* We have to clear errno and examine it later, because -1 is a
1608 legal return value for getpriority(). */
1609 errno = 0;
1610 ret = getpriority (cwhich, cwho);
1611 if (errno != 0)
1612 SCM_SYSERROR;
a55c2b68 1613 return scm_from_int (ret);
94e6d793
MG
1614}
1615#undef FUNC_NAME
1616#endif /* HAVE_GETPRIORITY */
1617
1618#if HAVE_SETPRIORITY
1619SCM_DEFINE (scm_setpriority, "setpriority", 3, 0, 0,
1620 (SCM which, SCM who, SCM prio),
1621 "Set the scheduling priority of the process, process group\n"
1622 "or user, as indicated by @var{which} and @var{who}. @var{which}\n"
1623 "is one of the variables @code{PRIO_PROCESS}, @code{PRIO_PGRP}\n"
1624 "or @code{PRIO_USER}, and @var{who} is interpreted relative to\n"
1625 "@var{which} (a process identifier for @code{PRIO_PROCESS},\n"
1626 "process group identifier for @code{PRIO_PGRP}, and a user\n"
1627 "identifier for @code{PRIO_USER}. A zero value of @var{who}\n"
1628 "denotes the current process, process group, or user.\n"
1629 "@var{prio} is a value in the range -20 and 20, the default\n"
1630 "priority is 0; lower priorities cause more favorable\n"
1631 "scheduling. Sets the priority of all of the specified\n"
1632 "processes. Only the super-user may lower priorities.\n"
1633 "The return value is not specified.")
1634#define FUNC_NAME s_scm_setpriority
1635{
1636 int cwhich, cwho, cprio;
1637
a55c2b68
MV
1638 cwhich = scm_to_int (which);
1639 cwho = scm_to_int (who);
1640 cprio = scm_to_int (prio);
94e6d793
MG
1641
1642 if (setpriority (cwhich, cwho, cprio) == -1)
1643 SCM_SYSERROR;
1644 return SCM_UNSPECIFIED;
1645}
1646#undef FUNC_NAME
1647#endif /* HAVE_SETPRIORITY */
1648
1649#if HAVE_GETPASS
1650SCM_DEFINE (scm_getpass, "getpass", 1, 0, 0,
1651 (SCM prompt),
1652 "Display @var{prompt} to the standard error output and read\n"
1653 "a password from @file{/dev/tty}. If this file is not\n"
1654 "accessible, it reads from standard input. The password may be\n"
1655 "up to 127 characters in length. Additional characters and the\n"
1656 "terminating newline character are discarded. While reading\n"
1657 "the password, echoing and the generation of signals by special\n"
1658 "characters is disabled.")
1659#define FUNC_NAME s_scm_getpass
1660{
1661 char * p;
1662 SCM passwd;
1663
1664 SCM_VALIDATE_STRING (1, prompt);
94e6d793 1665
f015614a
MV
1666 WITH_STRING (prompt, c_prompt,
1667 p = getpass(c_prompt));
1668 passwd = scm_from_locale_string (p);
94e6d793
MG
1669
1670 /* Clear out the password in the static buffer. */
1671 memset (p, 0, strlen (p));
1672
1673 return passwd;
1674}
1675#undef FUNC_NAME
1676#endif /* HAVE_GETPASS */
1677
8f99e3f3
SJ
1678/* Wrapper function for flock() support under M$-Windows. */
1679#ifdef __MINGW32__
1680# include <io.h>
1681# include <sys/locking.h>
1682# include <errno.h>
1683# ifndef _LK_UNLCK
1684 /* Current MinGW package fails to define this. *sigh* */
1685# define _LK_UNLCK 0
1686# endif
1687# define LOCK_EX 1
1688# define LOCK_UN 2
1689# define LOCK_SH 4
1690# define LOCK_NB 8
1691
1692static int flock (int fd, int operation)
1693{
1694 long pos, len;
1695 int ret, err;
1696
1697 /* Disable invalid arguments. */
1698 if (((operation & (LOCK_EX | LOCK_SH)) == (LOCK_EX | LOCK_SH)) ||
1699 ((operation & (LOCK_EX | LOCK_UN)) == (LOCK_EX | LOCK_UN)) ||
1700 ((operation & (LOCK_SH | LOCK_UN)) == (LOCK_SH | LOCK_UN)))
1701 {
1702 errno = EINVAL;
1703 return -1;
1704 }
1705
1706 /* Determine mode of operation and discard unsupported ones. */
1707 if (operation == (LOCK_NB | LOCK_EX))
1708 operation = _LK_NBLCK;
1709 else if (operation & LOCK_UN)
1710 operation = _LK_UNLCK;
1711 else if (operation == LOCK_EX)
1712 operation = _LK_LOCK;
1713 else
1714 {
1715 errno = EINVAL;
1716 return -1;
1717 }
1718
1719 /* Save current file pointer and seek to beginning. */
1720 if ((pos = lseek (fd, 0, SEEK_CUR)) == -1 || (len = filelength (fd)) == -1)
1721 return -1;
1722 lseek (fd, 0L, SEEK_SET);
1723
1724 /* Deadlock if necessary. */
1725 do
1726 {
1727 ret = _locking (fd, operation, len);
1728 }
1729 while (ret == -1 && errno == EDEADLOCK);
1730
1731 /* Produce meaningful error message. */
1732 if (errno == EACCES && operation == _LK_NBLCK)
1733 err = EDEADLOCK;
1734 else
1735 err = errno;
1736
1737 /* Return to saved file position pointer. */
1738 lseek (fd, pos, SEEK_SET);
1739 errno = err;
1740 return ret;
1741}
1742#endif /* __MINGW32__ */
1743
1744#if HAVE_FLOCK || defined (__MINGW32__)
94e6d793
MG
1745SCM_DEFINE (scm_flock, "flock", 2, 0, 0,
1746 (SCM file, SCM operation),
1747 "Apply or remove an advisory lock on an open file.\n"
1748 "@var{operation} specifies the action to be done:\n"
1749 "@table @code\n"
1750 "@item LOCK_SH\n"
1751 "Shared lock. More than one process may hold a shared lock\n"
1752 "for a given file at a given time.\n"
1753 "@item LOCK_EX\n"
1754 "Exclusive lock. Only one process may hold an exclusive lock\n"
1755 "for a given file at a given time.\n"
1756 "@item LOCK_UN\n"
1757 "Unlock the file.\n"
1758 "@item LOCK_NB\n"
1759 "Don't block when locking. May be specified by bitwise OR'ing\n"
1760 "it to one of the other operations.\n"
1761 "@end table\n"
1762 "The return value is not specified. @var{file} may be an open\n"
bb2c02f2 1763 "file descriptor or an open file descriptor port.")
94e6d793
MG
1764#define FUNC_NAME s_scm_flock
1765{
a55c2b68 1766 int fdes;
94e6d793 1767
a55c2b68
MV
1768 if (scm_is_integer (file))
1769 fdes = scm_to_int (file);
94e6d793
MG
1770 else
1771 {
1772 SCM_VALIDATE_OPFPORT (2, file);
1773
1774 fdes = SCM_FPORT_FDES (file);
1775 }
a55c2b68 1776 if (flock (fdes, scm_to_int (operation)) == -1)
94e6d793
MG
1777 SCM_SYSERROR;
1778 return SCM_UNSPECIFIED;
1779}
1780#undef FUNC_NAME
1781#endif /* HAVE_FLOCK */
1782
1783#if HAVE_SETHOSTNAME
1784SCM_DEFINE (scm_sethostname, "sethostname", 1, 0, 0,
1785 (SCM name),
1786 "Set the host name of the current processor to @var{name}. May\n"
1787 "only be used by the superuser. The return value is not\n"
1788 "specified.")
1789#define FUNC_NAME s_scm_sethostname
1790{
f015614a 1791 int rv;
94e6d793 1792
f015614a
MV
1793 WITH_STRING (name, c_name,
1794 rv = sethostname (c_name, strlen(c_name)));
1795 if (rv == -1)
94e6d793
MG
1796 SCM_SYSERROR;
1797 return SCM_UNSPECIFIED;
1798}
1799#undef FUNC_NAME
1800#endif /* HAVE_SETHOSTNAME */
1801
b28f5b3c 1802
94e6d793
MG
1803#if HAVE_GETHOSTNAME
1804SCM_DEFINE (scm_gethostname, "gethostname", 0, 0, 0,
1805 (void),
1806 "Return the host name of the current processor.")
1807#define FUNC_NAME s_scm_gethostname
1808{
b28f5b3c
DH
1809#ifdef MAXHOSTNAMELEN
1810
1811 /* Various systems define MAXHOSTNAMELEN (including Solaris in fact).
1812 * On GNU/Linux this doesn't include the terminating '\0', hence "+ 1". */
1813 const int len = MAXHOSTNAMELEN + 1;
1814 char *const p = scm_malloc (len);
1815 const int res = gethostname (p, len);
1816
1817 scm_frame_begin (0);
1818 scm_frame_unwind_handler (free, p, 0);
1819
1820#else
94e6d793 1821
0eaf1055 1822 /* Default 256 is for Solaris, under Linux ENAMETOOLONG is returned if not
b28f5b3c
DH
1823 * large enough. SUSv2 specifies 255 maximum too, apparently. */
1824 int len = 256;
1825 int res;
1826 char *p;
0eaf1055 1827
b28f5b3c 1828# if HAVE_SYSCONF && defined (_SC_HOST_NAME_MAX)
0eaf1055
KR
1829
1830 /* POSIX specifies the HOST_NAME_MAX system parameter for the max size,
b28f5b3c
DH
1831 * which may reflect a particular kernel configuration.
1832 * Must watch out for this existing but giving -1, as happens for instance
1833 * in gnu/linux glibc 2.3.2. */
0eaf1055 1834 {
b28f5b3c 1835 const long int n = sysconf (_SC_HOST_NAME_MAX);
0eaf1055
KR
1836 if (n != -1L)
1837 len = n;
1838 }
b28f5b3c
DH
1839
1840# endif
1841
1842 p = scm_malloc (len);
1843
1844 scm_frame_begin (0);
1845 scm_frame_unwind_handler (free, p, 0);
0eaf1055 1846
94e6d793
MG
1847 res = gethostname (p, len);
1848 while (res == -1 && errno == ENAMETOOLONG)
1849 {
94e6d793 1850 len *= 2;
b28f5b3c
DH
1851
1852 /* scm_realloc may throw an exception. */
1853 p = scm_realloc (p, len);
94e6d793
MG
1854 res = gethostname (p, len);
1855 }
b28f5b3c
DH
1856
1857#endif
1858
94e6d793
MG
1859 if (res == -1)
1860 {
b28f5b3c
DH
1861 const int save_errno = errno;
1862
1863 // No guile exceptions can occur before we have freed p's memory.
1864 scm_frame_end ();
4c9419ac 1865 free (p);
b28f5b3c 1866
22865124 1867 errno = save_errno;
94e6d793
MG
1868 SCM_SYSERROR;
1869 }
b28f5b3c
DH
1870 else
1871 {
cc95e00a
MV
1872 /* scm_from_locale_string may throw an exception. */
1873 const SCM name = scm_from_locale_string (p);
b28f5b3c
DH
1874
1875 // No guile exceptions can occur before we have freed p's memory.
1876 scm_frame_end ();
1877 free (p);
1878
1879 return name;
1880 }
94e6d793
MG
1881}
1882#undef FUNC_NAME
1883#endif /* HAVE_GETHOSTNAME */
1884
b28f5b3c 1885
0f2d19dd
JB
1886void
1887scm_init_posix ()
0f2d19dd
JB
1888{
1889 scm_add_feature ("posix");
1890#ifdef HAVE_GETEUID
1891 scm_add_feature ("EIDs");
1892#endif
1893#ifdef WAIT_ANY
e11e83f3 1894 scm_c_define ("WAIT_ANY", scm_from_int (WAIT_ANY));
0f2d19dd
JB
1895#endif
1896#ifdef WAIT_MYPGRP
e11e83f3 1897 scm_c_define ("WAIT_MYPGRP", scm_from_int (WAIT_MYPGRP));
0f2d19dd
JB
1898#endif
1899#ifdef WNOHANG
e11e83f3 1900 scm_c_define ("WNOHANG", scm_from_int (WNOHANG));
0f2d19dd
JB
1901#endif
1902#ifdef WUNTRACED
e11e83f3 1903 scm_c_define ("WUNTRACED", scm_from_int (WUNTRACED));
0f2d19dd
JB
1904#endif
1905
0f2d19dd 1906 /* access() symbols. */
e11e83f3
MV
1907 scm_c_define ("R_OK", scm_from_int (R_OK));
1908 scm_c_define ("W_OK", scm_from_int (W_OK));
1909 scm_c_define ("X_OK", scm_from_int (X_OK));
1910 scm_c_define ("F_OK", scm_from_int (F_OK));
0f2d19dd
JB
1911
1912#ifdef LC_COLLATE
e11e83f3 1913 scm_c_define ("LC_COLLATE", scm_from_int (LC_COLLATE));
0f2d19dd
JB
1914#endif
1915#ifdef LC_CTYPE
e11e83f3 1916 scm_c_define ("LC_CTYPE", scm_from_int (LC_CTYPE));
0f2d19dd
JB
1917#endif
1918#ifdef LC_MONETARY
e11e83f3 1919 scm_c_define ("LC_MONETARY", scm_from_int (LC_MONETARY));
0f2d19dd
JB
1920#endif
1921#ifdef LC_NUMERIC
e11e83f3 1922 scm_c_define ("LC_NUMERIC", scm_from_int (LC_NUMERIC));
0f2d19dd
JB
1923#endif
1924#ifdef LC_TIME
e11e83f3 1925 scm_c_define ("LC_TIME", scm_from_int (LC_TIME));
0f2d19dd
JB
1926#endif
1927#ifdef LC_MESSAGES
e11e83f3 1928 scm_c_define ("LC_MESSAGES", scm_from_int (LC_MESSAGES));
0f2d19dd
JB
1929#endif
1930#ifdef LC_ALL
e11e83f3 1931 scm_c_define ("LC_ALL", scm_from_int (LC_ALL));
0f2d19dd 1932#endif
9361f762
MV
1933#ifdef LC_PAPER
1934 scm_c_define ("LC_PAPER", scm_from_int (LC_PAPER));
1935#endif
1936#ifdef LC_NAME
1937 scm_c_define ("LC_NAME", scm_from_int (LC_NAME));
1938#endif
1939#ifdef LC_ADDRESS
1940 scm_c_define ("LC_ADDRESS", scm_from_int (LC_ADDRESS));
1941#endif
1942#ifdef LC_TELEPHONE
1943 scm_c_define ("LC_TELEPHONE", scm_from_int (LC_TELEPHONE));
1944#endif
1945#ifdef LC_MEASUREMENT
1946 scm_c_define ("LC_MEASUREMENT", scm_from_int (LC_MEASUREMENT));
1947#endif
1948#ifdef LC_IDENTIFICATION
1949 scm_c_define ("LC_IDENTIFICATION", scm_from_int (LC_IDENTIFICATION));
1950#endif
bd9e24b3 1951#ifdef PIPE_BUF
b9bd8526 1952 scm_c_define ("PIPE_BUF", scm_from_long (PIPE_BUF));
bd9e24b3
GH
1953#endif
1954
94e6d793 1955#ifdef PRIO_PROCESS
e11e83f3 1956 scm_c_define ("PRIO_PROCESS", scm_from_int (PRIO_PROCESS));
94e6d793
MG
1957#endif
1958#ifdef PRIO_PGRP
e11e83f3 1959 scm_c_define ("PRIO_PGRP", scm_from_int (PRIO_PGRP));
94e6d793
MG
1960#endif
1961#ifdef PRIO_USER
e11e83f3 1962 scm_c_define ("PRIO_USER", scm_from_int (PRIO_USER));
94e6d793
MG
1963#endif
1964
1965#ifdef LOCK_SH
e11e83f3 1966 scm_c_define ("LOCK_SH", scm_from_int (LOCK_SH));
94e6d793
MG
1967#endif
1968#ifdef LOCK_EX
e11e83f3 1969 scm_c_define ("LOCK_EX", scm_from_int (LOCK_EX));
94e6d793
MG
1970#endif
1971#ifdef LOCK_UN
e11e83f3 1972 scm_c_define ("LOCK_UN", scm_from_int (LOCK_UN));
94e6d793
MG
1973#endif
1974#ifdef LOCK_NB
e11e83f3 1975 scm_c_define ("LOCK_NB", scm_from_int (LOCK_NB));
94e6d793
MG
1976#endif
1977
a0599745
MD
1978#include "libguile/cpp_sig_symbols.c"
1979#include "libguile/posix.x"
0f2d19dd 1980}
89e00824
ML
1981
1982/*
1983 Local Variables:
1984 c-file-style: "gnu"
1985 End:
1986*/