1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* POSIX module implementation */
27 #include "allobjects.h"
28 #include "modsupport.h"
33 #include <sys/types.h>
36 #include "mytime.h" /* For clock_t on some systems */
40 #endif /* HAVE_FCNTL_H */
45 #else /* !HAVE_UNISTD_H */
46 extern int mkdir
PROTO((const char *, mode_t
));
47 extern int chdir
PROTO((const char *));
48 extern int rmdir
PROTO((const char *));
49 extern int chmod
PROTO((const char *, mode_t
));
50 extern int chown
PROTO((const char *, uid_t
, gid_t
));
51 extern char *getcwd
PROTO((char *, int));
52 extern char *strerror
PROTO((int));
53 extern int link
PROTO((const char *, const char *));
54 extern int rename
PROTO((const char *, const char *));
55 extern int stat
PROTO((const char *, struct stat
*));
56 extern int unlink
PROTO((const char *));
57 extern int pclose
PROTO((FILE *));
59 extern int symlink
PROTO((const char *, const char *));
60 #endif /_ HAVE_SYMLINK */
62 extern int lstat
PROTO((const char *, struct stat
*));
63 #endif /* HAVE_LSTAT */
64 #endif /* !HAVE_UNISTD_H */
68 /* XXX These are for SunOS4.1.3 but shouldn't hurt elsewhere */
77 #endif /* HAVE_UTIME_H */
79 #ifdef HAVE_SYS_UTIME_H
80 #include <sys/utime.h>
81 #define HAVE_UTIME_H /* pretend we do for the rest of this file */
82 #endif /* HAVE_SYS_UTIME_H */
84 #ifdef HAVE_SYS_TIMES_H
85 #include <sys/times.h>
86 #endif /* HAVE_SYS_TIMES_H */
88 #ifdef HAVE_SYS_PARAM_H
89 #include <sys/param.h>
90 #endif /* HAVE_SYS_PARAM_H */
92 #ifdef HAVE_SYS_UTSNAME_H
93 #include <sys/utsname.h>
94 #endif /* HAVE_SYS_UTSNAME_H */
97 #define MAXPATHLEN 1024
98 #endif /* MAXPATHLEN */
102 #define NAMLEN(dirent) strlen((dirent)->d_name)
104 #define dirent direct
105 #define NAMLEN(dirent) (dirent)->d_namlen
106 #ifdef HAVE_SYS_NDIR_H
107 #include <sys/ndir.h>
109 #ifdef HAVE_SYS_DIR_H
123 #define pclose _pclose
130 /* Return a dictionary corresponding to the POSIX environment table */
133 extern char **environ
;
146 /* XXX This part ignores errors */
147 for (e
= environ
; *e
!= NULL
; e
++) {
149 char *p
= strchr(*e
, '=');
152 v
= newstringobject(p
+1);
156 (void) dictinsert(d
, *e
, v
);
164 static object
*PosixError
; /* Exception posix.error */
166 /* Set a POSIX-specific error from errno, and return NULL */
168 static object
* posix_error() { return err_errno(PosixError
);
172 /* POSIX generic methods */
175 posix_1str(args
, func
)
177 int (*func
) FPROTO((const char *));
181 if (!getargs(args
, "s", &path1
))
184 res
= (*func
)(path1
);
187 return posix_error();
193 posix_2str(args
, func
)
195 int (*func
) FPROTO((const char *, const char *));
199 if (!getargs(args
, "(ss)", &path1
, &path2
))
202 res
= (*func
)(path1
, path2
);
205 return posix_error();
211 posix_strint(args
, func
)
213 int (*func
) FPROTO((const char *, int));
218 if (!getargs(args
, "(si)", &path
, &i
))
221 res
= (*func
)(path
, i
);
224 return posix_error();
230 posix_strintint(args
, func
)
232 int (*func
) FPROTO((const char *, int, int));
237 if (!getargs(args
, "(sii)", &path
, &i
, &i2
))
240 res
= (*func
)(path
, i
, i2
);
243 return posix_error();
249 posix_do_stat(self
, args
, statfunc
)
252 int (*statfunc
) FPROTO((const char *, struct stat
*));
257 if (!getargs(args
, "s", &path
))
260 res
= (*statfunc
)(path
, &st
);
263 return posix_error();
264 return mkvalue("(llllllllll)",
281 posix_chdir(self
, args
)
285 return posix_1str(args
, chdir
);
289 posix_chmod(self
, args
)
293 return posix_strint(args
, chmod
);
298 posix_chown(self
, args
)
302 return posix_strintint(args
, chown
);
304 #endif /* HAVE_CHOWN */
307 posix_getcwd(self
, args
)
316 res
= getcwd(buf
, sizeof buf
);
319 return posix_error();
320 return newstringobject(buf
);
325 posix_link(self
, args
)
329 return posix_2str(args
, link
);
331 #endif /* HAVE_LINK */
334 posix_listdir(self
, args
)
344 WIN32_FIND_DATA FileData
;
345 char namebuf
[MAX_PATH
+5];
347 if (!getargs(args
, "s#", &name
, &len
))
349 if (len
>= MAX_PATH
) {
350 err_setstr(ValueError
, "path too long");
353 strcpy(namebuf
, name
);
354 if (namebuf
[len
-1] != '/' && namebuf
[len
-1] != '\\')
355 namebuf
[len
++] = '/';
356 strcpy(namebuf
+ len
, "*.*");
358 if ((d
= newlistobject(0)) == NULL
)
361 hFindFile
= FindFirstFile(namebuf
, &FileData
);
362 if (hFindFile
== INVALID_HANDLE_VALUE
) {
363 errno
= GetLastError();
364 return posix_error();
367 v
= newstringobject(FileData
.cFileName
);
373 if (addlistitem(d
, v
) != 0) {
380 } while (FindNextFile(hFindFile
, &FileData
) == TRUE
);
382 if (FindClose(hFindFile
) == FALSE
) {
383 errno
= GetLastError();
384 return posix_error();
395 if (!getargs(args
, "s", &name
))
398 if ((dirp
= opendir(name
)) == NULL
) {
400 return posix_error();
402 if ((d
= newlistobject(0)) == NULL
) {
407 while ((ep
= readdir(dirp
)) != NULL
) {
408 v
= newsizedstringobject(ep
->d_name
, NAMLEN(ep
));
414 if (addlistitem(d
, v
) != 0) {
431 posix_mkdir(self
, args
)
435 return posix_strint(args
, mkdir
);
440 posix_nice(self
, args
)
444 int increment
, value
;
446 if (!getargs(args
, "i", &increment
))
448 value
= nice(increment
);
450 return posix_error();
451 return newintobject((long) value
);
453 #endif /* HAVE_NICE */
456 posix_rename(self
, args
)
460 return posix_2str(args
, rename
);
464 posix_rmdir(self
, args
)
468 return posix_1str(args
, rmdir
);
472 posix_stat(self
, args
)
476 return posix_do_stat(self
, args
, stat
);
480 posix_system(self
, args
)
486 if (!getargs(args
, "s", &command
))
489 sts
= system(command
);
491 return newintobject(sts
);
495 posix_umask(self
, args
)
500 if (!getintarg(args
, &i
))
504 return posix_error();
505 return newintobject((long)i
);
509 posix_unlink(self
, args
)
513 return posix_1str(args
, unlink
);
518 posix_uname(self
, args
)
531 return posix_error();
532 return mkvalue("(sssss)",
539 #endif /* HAVE_UNAME */
542 posix_utime(self
, args
)
551 #define ATIME buf.actime
552 #define MTIME buf.modtime
553 #define UTIME_ARG &buf
554 #else /* HAVE_UTIME_H */
558 #define UTIME_ARG buf
559 #endif /* HAVE_UTIME_H */
561 if (!getargs(args
, "(s(ll))", &path
, &ATIME
, &MTIME
))
564 res
= utime(path
, UTIME_ARG
);
567 return posix_error();
576 /* Process operations */
579 posix__exit(self
, args
)
584 if (!getintarg(args
, &sts
))
591 posix_execv(self
, args
)
599 object
*(*getitem
) PROTO((object
*, int));
601 /* execv has two arguments: (path, argv), where
602 argv is a list or tuple of strings. */
604 if (!getargs(args
, "(sO)", &path
, &argv
))
606 if (is_listobject(argv
)) {
607 argc
= getlistsize(argv
);
608 getitem
= getlistitem
;
610 else if (is_tupleobject(argv
)) {
611 argc
= gettuplesize(argv
);
612 getitem
= gettupleitem
;
620 argvlist
= NEW(char *, argc
+1);
621 if (argvlist
== NULL
)
623 for (i
= 0; i
< argc
; i
++) {
624 if (!getargs((*getitem
)(argv
, i
), "s", &argvlist
[i
])) {
629 argvlist
[argc
] = NULL
;
631 #ifdef BAD_EXEC_PROTOTYPES
632 execv(path
, (const char **) argvlist
);
633 #else /* BAD_EXEC_PROTOTYPES */
634 execv(path
, argvlist
);
635 #endif /* BAD_EXEC_PROTOTYPES */
637 /* If we get here it's definitely an error */
640 return posix_error();
644 posix_execve(self
, args
)
653 int i
, pos
, argc
, envc
;
654 object
*(*getitem
) PROTO((object
*, int));
656 /* execve has three arguments: (path, argv, env), where
657 argv is a list or tuple of strings and env is a dictionary
658 like posix.environ. */
660 if (!getargs(args
, "(sOO)", &path
, &argv
, &env
))
662 if (is_listobject(argv
)) {
663 argc
= getlistsize(argv
);
664 getitem
= getlistitem
;
666 else if (is_tupleobject(argv
)) {
667 argc
= gettuplesize(argv
);
668 getitem
= gettupleitem
;
671 err_setstr(TypeError
, "argv must be tuple or list");
674 if (!is_dictobject(env
)) {
675 err_setstr(TypeError
, "env must be dictionary");
679 argvlist
= NEW(char *, argc
+1);
680 if (argvlist
== NULL
) {
684 for (i
= 0; i
< argc
; i
++) {
685 if (!getargs((*getitem
)(argv
, i
),
686 "s;argv must be list of strings",
691 argvlist
[argc
] = NULL
;
693 i
= getmappingsize(env
);
694 envlist
= NEW(char *, i
+ 1);
695 if (envlist
== NULL
) {
701 while (mappinggetnext(env
, &pos
, &key
, &val
)) {
703 if (!getargs(key
, "s;non-string key in env", &k
) ||
704 !getargs(val
, "s;non-string value in env", &v
)) {
707 p
= NEW(char, getstringsize(key
) + getstringsize(val
) + 2);
712 sprintf(p
, "%s=%s", k
, v
);
718 #ifdef BAD_EXEC_PROTOTYPES
719 execve(path
, (const char **)argvlist
, envlist
);
720 #else /* BAD_EXEC_PROTOTYPES */
721 execve(path
, argvlist
, envlist
);
722 #endif /* BAD_EXEC_PROTOTYPES */
724 /* If we get here it's definitely an error */
726 (void) posix_error();
740 posix_fork(self
, args
)
749 return posix_error();
750 return newintobject((long)pid
);
754 posix_getegid(self
, args
)
760 return newintobject((long)getegid());
764 posix_geteuid(self
, args
)
770 return newintobject((long)geteuid());
774 posix_getgid(self
, args
)
780 return newintobject((long)getgid());
785 posix_getpid(self
, args
)
791 return newintobject((long)getpid());
796 posix_getpgrp(self
, args
)
802 #ifdef GETPGRP_HAVE_ARG
803 return newintobject((long)getpgrp(0));
804 #else /* GETPGRP_HAVE_ARG */
805 return newintobject((long)getpgrp());
806 #endif /* GETPGRP_HAVE_ARG */
808 #endif /* HAVE_GETPGRP */
812 posix_setpgrp(self
, args
)
818 #ifdef SETPGRP_HAVE_ARG
819 if (setpgrp(0, 0) < 0)
820 #else /* SETPGRP_HAVE_ARG */
822 #endif /* SETPGRP_HAVE_ARG */
823 return posix_error();
828 #endif /* HAVE_SETPGRP */
832 posix_getppid(self
, args
)
838 return newintobject((long)getppid());
842 posix_getuid(self
, args
)
848 return newintobject((long)getuid());
852 posix_kill(self
, args
)
857 if (!getargs(args
, "(ii)", &pid
, &sig
))
859 if (kill(pid
, sig
) == -1)
860 return posix_error();
867 posix_popen(self
, args
)
876 if (!newgetargs(args
, "s|si", &name
, &mode
, &bufsize
))
879 fp
= popen(name
, mode
);
882 return posix_error();
883 f
= newopenfileobject(fp
, name
, mode
, pclose
);
885 setfilebufsize(f
, bufsize
);
891 posix_setuid(self
, args
)
896 if (!getargs(args
, "i", &uid
))
899 return posix_error();
903 #endif /* HAVE_SETUID */
907 posix_setgid(self
, args
)
912 if (!getargs(args
, "i", &gid
))
915 return posix_error();
919 #endif /* HAVE_SETGID */
923 posix_waitpid(self
, args
)
927 int pid
, options
, sts
;
928 if (!getargs(args
, "(ii)", &pid
, &options
))
931 pid
= waitpid(pid
, &sts
, options
);
934 return posix_error();
936 return mkvalue("ii", pid
, sts
);
938 #endif /* HAVE_WAITPID */
942 posix_wait(self
, args
)
951 return posix_error();
953 return mkvalue("ii", pid
, sts
);
958 posix_lstat(self
, args
)
963 return posix_do_stat(self
, args
, lstat
);
964 #else /* !HAVE_LSTAT */
965 return posix_do_stat(self
, args
, stat
);
966 #endif /* !HAVE_LSTAT */
971 posix_readlink(self
, args
)
975 char buf
[MAXPATHLEN
];
978 if (!getargs(args
, "s", &path
))
981 n
= readlink(path
, buf
, (int) sizeof buf
);
984 return posix_error();
985 return newsizedstringobject(buf
, n
);
987 #endif /* HAVE_READLINK */
991 posix_symlink(self
, args
)
995 return posix_2str(args
, symlink
);
997 #endif /* HAVE_SYMLINK */
1001 #define HZ 60 /* Universal constant :-) */
1004 posix_times(self
, args
)
1010 if (!getnoarg(args
))
1014 if (c
== (clock_t) -1)
1015 return posix_error();
1016 return mkvalue("dddd",
1017 (double)t
.tms_utime
/ HZ
,
1018 (double)t
.tms_stime
/ HZ
,
1019 (double)t
.tms_cutime
/ HZ
,
1020 (double)t
.tms_cstime
/ HZ
);
1022 #endif /* HAVE_TIMES */
1024 #define HAVE_TIMES /* so the method table will pick it up */
1026 posix_times(self
, args
)
1030 FILETIME create
, exit
, kernel
, user
;
1032 if (!getnoarg(args
))
1034 hProc
= GetCurrentProcess();
1035 GetProcessTimes(hProc
,&create
, &exit
, &kernel
, &user
);
1036 return mkvalue("dddd",
1037 (double)(kernel
.dwHighDateTime
*2E32
+kernel
.dwLowDateTime
) / 2E6
,
1038 (double)(user
.dwHighDateTime
*2E32
+user
.dwLowDateTime
) / 2E6
,
1046 posix_setsid(self
, args
)
1050 if (!getnoarg(args
))
1053 return posix_error();
1057 #endif /* HAVE_SETSID */
1061 posix_setpgid(self
, args
)
1066 if (!getargs(args
, "(ii)", &pid
, &pgrp
))
1068 if (setpgid(pid
, pgrp
) < 0)
1069 return posix_error();
1073 #endif /* HAVE_SETPGID */
1075 #ifdef HAVE_TCGETPGRP
1077 posix_tcgetpgrp(self
, args
)
1082 if (!getargs(args
, "i", &fd
))
1084 pgid
= tcgetpgrp(fd
);
1086 return posix_error();
1087 return newintobject((long)pgid
);
1089 #endif /* HAVE_TCGETPGRP */
1091 #ifdef HAVE_TCSETPGRP
1093 posix_tcsetpgrp(self
, args
)
1098 if (!getargs(args
, "(ii)", &fd
, &pgid
))
1100 if (tcsetpgrp(fd
, pgid
) < 0)
1101 return posix_error();
1105 #endif /* HAVE_TCSETPGRP */
1107 /* Functions acting on file descriptors */
1110 posix_open(self
, args
)
1118 if (!getargs(args
, "(si)", &file
, &flag
)) {
1120 if (!getargs(args
, "(sii)", &file
, &flag
, &mode
))
1124 fd
= open(file
, flag
, mode
);
1127 return posix_error();
1128 return newintobject((long)fd
);
1132 posix_close(self
, args
)
1137 if (!getargs(args
, "i", &fd
))
1143 return posix_error();
1149 posix_dup(self
, args
)
1154 if (!getargs(args
, "i", &fd
))
1160 return posix_error();
1161 return newintobject((long)fd
);
1165 posix_dup2(self
, args
)
1170 if (!getargs(args
, "(ii)", &fd
, &fd2
))
1173 res
= dup2(fd
, fd2
);
1176 return posix_error();
1182 posix_lseek(self
, args
)
1188 if (!getargs(args
, "(ili)", &fd
, &pos
, &how
))
1191 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
1193 case 0: how
= SEEK_SET
; break;
1194 case 1: how
= SEEK_CUR
; break;
1195 case 2: how
= SEEK_END
; break;
1197 #endif /* SEEK_END */
1199 res
= lseek(fd
, pos
, how
);
1202 return posix_error();
1203 return newintobject(res
);
1207 posix_read(self
, args
)
1213 if (!getargs(args
, "(ii)", &fd
, &size
))
1215 buffer
= newsizedstringobject((char *)NULL
, size
);
1219 size
= read(fd
, getstringvalue(buffer
), size
);
1223 return posix_error();
1225 resizestring(&buffer
, size
);
1230 posix_write(self
, args
)
1236 if (!getargs(args
, "(is#)", &fd
, &buffer
, &size
))
1239 size
= write(fd
, buffer
, size
);
1242 return posix_error();
1243 return newintobject((long)size
);
1247 posix_fstat(self
, args
)
1254 if (!getargs(args
, "i", &fd
))
1257 res
= fstat(fd
, &st
);
1260 return posix_error();
1261 return mkvalue("(llllllllll)",
1275 posix_fdopen(self
, args
)
1279 extern int fclose
PROTO((FILE *));
1285 if (!newgetargs(args
, "i|si", &fd
, &mode
, &bufsize
))
1288 fp
= fdopen(fd
, mode
);
1291 return posix_error();
1292 f
= newopenfileobject(fp
, "(fdopen)", mode
, fclose
);
1294 setfilebufsize(f
, bufsize
);
1299 posix_pipe(self
, args
)
1306 if (!getargs(args
, ""))
1312 return posix_error();
1313 return mkvalue("(ii)", fds
[0], fds
[1]);
1317 if (!getargs(args
, ""))
1320 ok
= CreatePipe( &read
, &write
, NULL
, 0);
1323 return posix_error();
1324 return mkvalue("(ii)", read
, write
);
1328 static struct methodlist posix_methods
[] = {
1329 {"chdir", posix_chdir
},
1330 {"chmod", posix_chmod
},
1332 {"chown", posix_chown
},
1333 #endif /* HAVE_CHOWN */
1334 {"getcwd", posix_getcwd
},
1336 {"link", posix_link
},
1337 #endif /* HAVE_LINK */
1338 {"listdir", posix_listdir
},
1339 {"lstat", posix_lstat
},
1340 {"mkdir", posix_mkdir
},
1342 {"nice", posix_nice
},
1343 #endif /* HAVE_NICE */
1344 #ifdef HAVE_READLINK
1345 {"readlink", posix_readlink
},
1346 #endif /* HAVE_READLINK */
1347 {"rename", posix_rename
},
1348 {"rmdir", posix_rmdir
},
1349 {"stat", posix_stat
},
1351 {"symlink", posix_symlink
},
1352 #endif /* HAVE_SYMLINK */
1353 {"system", posix_system
},
1354 {"umask", posix_umask
},
1356 {"uname", posix_uname
},
1357 #endif /* HAVE_UNAME */
1358 {"unlink", posix_unlink
},
1359 {"utime", posix_utime
},
1361 {"times", posix_times
},
1362 #endif /* HAVE_TIMES */
1363 {"_exit", posix__exit
},
1364 {"execv", posix_execv
},
1365 {"execve", posix_execve
},
1367 {"fork", posix_fork
},
1368 {"getegid", posix_getegid
},
1369 {"geteuid", posix_geteuid
},
1370 {"getgid", posix_getgid
},
1372 {"getpid", posix_getpid
},
1374 {"getpgrp", posix_getpgrp
},
1375 #endif /* HAVE_GETPGRP */
1377 {"getppid", posix_getppid
},
1378 {"getuid", posix_getuid
},
1379 {"kill", posix_kill
},
1381 {"popen", posix_popen
, 1},
1383 {"setuid", posix_setuid
},
1384 #endif /* HAVE_SETUID */
1386 {"setgid", posix_setgid
},
1387 #endif /* HAVE_SETGID */
1389 {"setpgrp", posix_setpgrp
},
1390 #endif /* HAVE_SETPGRP */
1392 {"wait", posix_wait
},
1395 {"waitpid", posix_waitpid
},
1396 #endif /* HAVE_WAITPID */
1398 {"setsid", posix_setsid
},
1399 #endif /* HAVE_SETSID */
1401 {"setpgid", posix_setpgid
},
1402 #endif /* HAVE_SETPGID */
1403 #ifdef HAVE_TCGETPGRP
1404 {"tcgetpgrp", posix_tcgetpgrp
},
1405 #endif /* HAVE_TCGETPGRP */
1406 #ifdef HAVE_TCSETPGRP
1407 {"tcsetpgrp", posix_tcsetpgrp
},
1408 #endif /* HAVE_TCSETPGRP */
1409 {"open", posix_open
},
1410 {"close", posix_close
},
1412 {"dup2", posix_dup2
},
1413 {"lseek", posix_lseek
},
1414 {"read", posix_read
},
1415 {"write", posix_write
},
1416 {"fstat", posix_fstat
},
1417 {"fdopen", posix_fdopen
, 1},
1418 {"pipe", posix_pipe
},
1419 {NULL
, NULL
} /* Sentinel */
1429 m
= initmodule("nt", posix_methods
);
1430 d
= getmoduledict(m
);
1432 /* Initialize nt.environ dictionary */
1433 v
= convertenviron();
1434 if (v
== NULL
|| dictinsert(d
, "environ", v
) != 0)
1435 fatal("can't define nt.environ");
1438 /* Initialize nt.error exception */
1439 PosixError
= newstringobject("nt.error");
1440 if (PosixError
== NULL
|| dictinsert(d
, "error", PosixError
) != 0)
1441 fatal("can't define nt.error");
1449 m
= initmodule("posix", posix_methods
);
1450 d
= getmoduledict(m
);
1452 /* Initialize posix.environ dictionary */
1453 v
= convertenviron();
1454 if (v
== NULL
|| dictinsert(d
, "environ", v
) != 0)
1455 fatal("can't define posix.environ");
1458 /* Initialize posix.error exception */
1459 PosixError
= newstringobject("posix.error");
1460 if (PosixError
== NULL
|| dictinsert(d
, "error", PosixError
) != 0)
1461 fatal("can't define posix.error");