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