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