1 /***********************************************************
2 Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
3 Amsterdam, The Netherlands.
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 */
31 #include "allobjects.h"
32 #include "modsupport.h"
39 #include <sys/types.h>
42 #include "mytime.h" /* For clock_t on some systems */
50 #else /* !HAVE_UNISTD_H */
51 extern int mkdir
PROTO((const char *, mode_t
));
52 extern int chdir
PROTO((const char *));
53 extern int rmdir
PROTO((const char *));
54 extern int chmod
PROTO((const char *, mode_t
));
55 extern int chown
PROTO((const char *, uid_t
, gid_t
));
56 extern char *getcwd
PROTO((char *, int));
57 extern char *strerror
PROTO((int));
58 extern int link
PROTO((const char *, const char *));
59 extern int rename
PROTO((const char *, const char *));
60 extern int stat
PROTO((const char *, struct stat
*));
61 extern int unlink
PROTO((const char *));
62 extern int pclose
PROTO((FILE *));
64 extern int symlink
PROTO((const char *, const char *));
67 extern int lstat
PROTO((const char *, struct stat
*));
69 #endif /* !HAVE_UNISTD_H */
72 /* XXX These are for SunOS4.1.3 but shouldn't hurt elsewhere */
83 #ifdef HAVE_SYS_TIMES_H
84 #include <sys/times.h>
87 #ifdef HAVE_SYS_PARAM_H
88 #include <sys/param.h>
91 #ifdef HAVE_SYS_UTSNAME_H
92 #include <sys/utsname.h>
96 #define MAXPATHLEN 1024
99 /* unistd.h defines _POSIX_VERSION on POSIX.1 systems. */
100 #if defined(DIRENT) || defined(_POSIX_VERSION)
102 #define NLENGTH(dirent) (strlen((dirent)->d_name))
103 #else /* not (DIRENT or _POSIX_VERSION) */
104 #define dirent direct
105 #define NLENGTH(dirent) ((dirent)->d_namlen)
107 #include <sys/ndir.h>
115 #endif /* not (DIRENT or _POSIX_VERSION) */
126 /* Return a dictionary corresponding to the POSIX environment table */
128 extern char **environ
;
140 /* XXX This part ignores errors */
141 for (e
= environ
; *e
!= NULL
; e
++) {
143 char *p
= strchr(*e
, '=');
146 v
= newstringobject(p
+1);
150 (void) dictinsert(d
, *e
, v
);
158 static object
*PosixError
; /* Exception posix.error */
160 /* Set a POSIX-specific error from errno, and return NULL */
162 static object
* posix_error() { return err_errno(PosixError
);
166 /* POSIX generic methods */
169 posix_1str(args
, func
)
171 int (*func
) FPROTO((const char *));
175 if (!getargs(args
, "s", &path1
))
178 res
= (*func
)(path1
);
181 return posix_error();
187 posix_2str(args
, func
)
189 int (*func
) FPROTO((const char *, const char *));
193 if (!getargs(args
, "(ss)", &path1
, &path2
))
196 res
= (*func
)(path1
, path2
);
199 return posix_error();
205 posix_strint(args
, func
)
207 int (*func
) FPROTO((const char *, int));
212 if (!getargs(args
, "(si)", &path
, &i
))
215 res
= (*func
)(path
, i
);
218 return posix_error();
224 posix_strintint(args
, func
)
226 int (*func
) FPROTO((const char *, int, int));
231 if (!getargs(args
, "(sii)", &path
, &i
, &i2
))
234 res
= (*func
)(path
, i
, i2
);
237 return posix_error();
243 posix_do_stat(self
, args
, statfunc
)
246 int (*statfunc
) FPROTO((const char *, struct stat
*));
251 if (!getargs(args
, "s", &path
))
254 res
= (*statfunc
)(path
, &st
);
257 return posix_error();
258 return mkvalue("(llllllllll)",
275 posix_chdir(self
, args
)
279 return posix_1str(args
, chdir
);
283 posix_chmod(self
, args
)
287 return posix_strint(args
, chmod
);
291 posix_chown(self
, args
)
295 return posix_strintint(args
, chown
);
299 posix_getcwd(self
, args
)
308 res
= getcwd(buf
, sizeof buf
);
311 return posix_error();
312 return newstringobject(buf
);
316 posix_link(self
, args
)
320 return posix_2str(args
, link
);
325 posix_listdir(self
, args
)
333 WIN32_FIND_DATA FileData
;
334 char namebuf
[MAX_PATH
+5];
336 if (!getargs(args
, "s#", &name
, &len
))
338 if (len
>= MAX_PATH
) {
339 err_setstr(ValueError
, "path too long");
342 strcpy(namebuf
, name
);
343 if (namebuf
[len
-1] != '/' && namebuf
[len
-1] != '\\')
344 namebuf
[len
++] = '/';
345 strcpy(namebuf
+ len
, "*.*");
347 if ((d
= newlistobject(0)) == NULL
)
350 hFindFile
= FindFirstFile(namebuf
, &FileData
);
351 if (hFindFile
== INVALID_HANDLE_VALUE
) {
352 errno
= GetLastError();
353 return posix_error();
356 v
= newstringobject(FileData
.cFileName
);
362 if (addlistitem(d
, v
) != 0) {
369 } while (FindNextFile(hFindFile
, &FileData
) == TRUE
);
371 if (FindClose(hFindFile
) == FALSE
) {
372 errno
= GetLastError();
373 return posix_error();
380 posix_listdir(self
, args
)
388 if (!getargs(args
, "s", &name
))
391 if ((dirp
= opendir(name
)) == NULL
) {
393 return posix_error();
395 if ((d
= newlistobject(0)) == NULL
) {
400 while ((ep
= readdir(dirp
)) != NULL
) {
401 v
= newstringobject(ep
->d_name
);
407 if (addlistitem(d
, v
) != 0) {
423 posix_mkdir(self
, args
)
427 return posix_strint(args
, mkdir
);
432 posix_nice(self
, args
)
436 int increment
, value
;
438 if (!getargs(args
, "i", &increment
))
440 value
= nice(increment
);
442 return posix_error();
443 return newintobject((long) value
);
445 #endif /* HAVE_NICE */
448 posix_rename(self
, args
)
452 return posix_2str(args
, rename
);
456 posix_rmdir(self
, args
)
460 return posix_1str(args
, rmdir
);
464 posix_stat(self
, args
)
468 return posix_do_stat(self
, args
, stat
);
472 posix_system(self
, args
)
478 if (!getargs(args
, "s", &command
))
481 sts
= system(command
);
483 return newintobject(sts
);
487 posix_umask(self
, args
)
492 if (!getintarg(args
, &i
))
496 return posix_error();
497 return newintobject((long)i
);
501 posix_unlink(self
, args
)
505 return posix_1str(args
, unlink
);
510 posix_uname(self
, args
)
523 return posix_error();
524 return mkvalue("(sssss)",
531 #endif /* HAVE_UNAME */
534 posix_utime(self
, args
)
543 #define ATIME buf.actime
544 #define MTIME buf.modtime
545 #define UTIME_ARG &buf
550 #define UTIME_ARG buf
553 if (!getargs(args
, "(s(ll))", &path
, &ATIME
, &MTIME
))
556 res
= utime(path
, UTIME_ARG
);
559 return posix_error();
568 /* Process operations */
571 posix__exit(self
, args
)
576 if (!getintarg(args
, &sts
))
583 posix_execv(self
, args
)
591 object
*(*getitem
) PROTO((object
*, int));
593 /* execv has two arguments: (path, argv), where
594 argv is a list or tuple of strings. */
596 if (!getargs(args
, "(sO)", &path
, &argv
))
598 if (is_listobject(argv
)) {
599 argc
= getlistsize(argv
);
600 getitem
= getlistitem
;
602 else if (is_tupleobject(argv
)) {
603 argc
= gettuplesize(argv
);
604 getitem
= gettupleitem
;
612 argvlist
= NEW(char *, argc
+1);
613 if (argvlist
== NULL
)
615 for (i
= 0; i
< argc
; i
++) {
616 if (!getargs((*getitem
)(argv
, i
), "s", &argvlist
[i
])) {
621 argvlist
[argc
] = NULL
;
623 #ifdef BAD_EXEC_PROTOTYPES
624 execv(path
, (const char **) argvlist
);
626 execv(path
, argvlist
);
629 /* If we get here it's definitely an error */
632 return posix_error();
636 posix_execve(self
, args
)
645 int i
, pos
, argc
, envc
;
646 object
*(*getitem
) PROTO((object
*, int));
648 /* execve has three arguments: (path, argv, env), where
649 argv is a list or tuple of strings and env is a dictionary
650 like posix.environ. */
652 if (!getargs(args
, "(sOO)", &path
, &argv
, &env
))
654 if (is_listobject(argv
)) {
655 argc
= getlistsize(argv
);
656 getitem
= getlistitem
;
658 else if (is_tupleobject(argv
)) {
659 argc
= gettuplesize(argv
);
660 getitem
= gettupleitem
;
663 err_setstr(TypeError
, "argv must be tuple or list");
666 if (!is_dictobject(env
)) {
667 err_setstr(TypeError
, "env must be dictionary");
671 argvlist
= NEW(char *, argc
+1);
672 if (argvlist
== NULL
) {
676 for (i
= 0; i
< argc
; i
++) {
677 if (!getargs((*getitem
)(argv
, i
),
678 "s;argv must be list of strings",
683 argvlist
[argc
] = NULL
;
685 i
= getmappingsize(env
);
686 envlist
= NEW(char *, i
+ 1);
687 if (envlist
== NULL
) {
693 while (mappinggetnext(env
, &pos
, &key
, &val
)) {
695 if (!getargs(key
, "s;non-string key in env", &k
) ||
696 !getargs(val
, "s;non-string value in env", &v
)) {
699 p
= NEW(char, getstringsize(key
) + getstringsize(val
) + 2);
704 sprintf(p
, "%s=%s", k
, v
);
710 #ifdef BAD_EXEC_PROTOTYPES
711 execve(path
, (const char **)argvlist
, envlist
);
713 execve(path
, argvlist
, envlist
);
716 /* If we get here it's definitely an error */
718 (void) posix_error();
731 posix_fork(self
, args
)
740 return posix_error();
741 return newintobject((long)pid
);
745 posix_getegid(self
, args
)
751 return newintobject((long)getegid());
755 posix_geteuid(self
, args
)
761 return newintobject((long)geteuid());
765 posix_getgid(self
, args
)
771 return newintobject((long)getgid());
775 posix_getpid(self
, args
)
781 return newintobject((long)getpid());
786 posix_getpgrp(self
, args
)
792 #ifdef GETPGRP_HAVE_ARG
793 return newintobject((long)getpgrp(0));
795 return newintobject((long)getpgrp());
798 #endif /* HAVE_GETPGRP */
802 posix_setpgrp(self
, args
)
808 #ifdef GETPGRP_HAVE_ARG
809 if (setpgrp(0, 0) < 0)
813 return posix_error();
818 #endif /* HAVE_SETPGRP */
821 posix_getppid(self
, args
)
827 return newintobject((long)getppid());
831 posix_getuid(self
, args
)
837 return newintobject((long)getuid());
841 posix_kill(self
, args
)
846 if (!getargs(args
, "(ii)", &pid
, &sig
))
848 if (kill(pid
, sig
) == -1)
849 return posix_error();
855 posix_popen(self
, args
)
861 if (!getargs(args
, "(ss)", &name
, &mode
))
864 fp
= popen(name
, mode
);
867 return posix_error();
868 /* From now on, ignore SIGPIPE and let the error checking
871 return newopenfileobject(fp
, name
, mode
, fclose
);
873 (void) signal(SIGPIPE
, SIG_IGN
);
874 return newopenfileobject(fp
, name
, mode
, pclose
);
879 posix_setuid(self
, args
)
884 if (!getargs(args
, "i", &uid
))
887 return posix_error();
893 posix_setgid(self
, args
)
898 if (!getargs(args
, "i", &gid
))
901 return posix_error();
908 posix_waitpid(self
, args
)
912 int pid
, options
, sts
;
913 if (!getargs(args
, "(ii)", &pid
, &options
))
916 pid
= waitpid(pid
, &sts
, options
);
919 return posix_error();
921 return mkvalue("ii", pid
, sts
);
923 #endif /* HAVE_WAITPID */
926 posix_wait(self
, args
)
935 return posix_error();
937 return mkvalue("ii", pid
, sts
);
941 posix_lstat(self
, args
)
946 return posix_do_stat(self
, args
, lstat
);
947 #else /* !HAVE_LSTAT */
948 return posix_do_stat(self
, args
, stat
);
949 #endif /* !HAVE_LSTAT */
954 posix_readlink(self
, args
)
958 char buf
[MAXPATHLEN
];
961 if (!getargs(args
, "s", &path
))
964 n
= readlink(path
, buf
, (int) sizeof buf
);
967 return posix_error();
968 return newsizedstringobject(buf
, n
);
970 #endif /* HAVE_READLINK */
974 posix_symlink(self
, args
)
978 return posix_2str(args
, symlink
);
980 #endif /* HAVE_SYMLINK */
984 #define HZ 60 /* Universal constant :-) */
987 posix_times(self
, args
)
997 if (c
== (clock_t) -1)
998 return posix_error();
999 return mkvalue("dddd",
1000 (double)t
.tms_utime
/ HZ
,
1001 (double)t
.tms_stime
/ HZ
,
1002 (double)t
.tms_cutime
/ HZ
,
1003 (double)t
.tms_cstime
/ HZ
);
1005 #endif /* HAVE_TIMES */
1009 posix_setsid(self
, args
)
1013 if (!getnoarg(args
))
1016 return posix_error();
1020 #endif /* HAVE_SETSID */
1024 posix_setpgid(self
, args
)
1029 if (!getargs(args
, "(ii)", &pid
, &pgrp
))
1031 if (setpgid(pid
, pgrp
) < 0)
1032 return posix_error();
1036 #endif /* HAVE_SETPGID */
1038 #ifdef HAVE_TCGETPGRP
1040 posix_tcgetpgrp(self
, args
)
1045 if (!getargs(args
, "i", &fd
))
1047 pgid
= tcgetpgrp(fd
);
1049 return posix_error();
1050 return newintobject((long)pgid
);
1052 #endif /* HAVE_TCGETPGRP */
1054 #ifdef HAVE_TCSETPGRP
1056 posix_tcsetpgrp(self
, args
)
1061 if (!getargs(args
, "(ii)", &fd
, &pgid
))
1063 if (tcsetpgrp(fd
, pgid
) < 0)
1064 return posix_error();
1068 #endif /* HAVE_TCSETPGRP */
1070 /* Functions acting on file descriptors */
1073 posix_open(self
, args
)
1081 if (!getargs(args
, "(si)", &file
, &flag
)) {
1083 if (!getargs(args
, "(sii)", &file
, &flag
, &mode
))
1087 fd
= open(file
, flag
, mode
);
1090 return posix_error();
1091 return newintobject((long)fd
);
1095 posix_close(self
, args
)
1100 if (!getargs(args
, "i", &fd
))
1106 return posix_error();
1112 posix_dup(self
, args
)
1117 if (!getargs(args
, "i", &fd
))
1123 return posix_error();
1124 return newintobject((long)fd
);
1128 posix_dup2(self
, args
)
1133 if (!getargs(args
, "(ii)", &fd
, &fd2
))
1136 res
= dup2(fd
, fd2
);
1139 return posix_error();
1145 posix_lseek(self
, args
)
1151 if (!getargs(args
, "(ili)", &fd
, &pos
, &how
))
1154 /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */
1156 case 0: how
= SEEK_SET
; break;
1157 case 1: how
= SEEK_CUR
; break;
1158 case 2: how
= SEEK_END
; break;
1162 res
= lseek(fd
, pos
, how
);
1165 return posix_error();
1166 return newintobject(res
);
1170 posix_read(self
, args
)
1176 if (!getargs(args
, "(ii)", &fd
, &size
))
1178 buffer
= newsizedstringobject((char *)NULL
, size
);
1182 size
= read(fd
, getstringvalue(buffer
), size
);
1186 return posix_error();
1188 resizestring(&buffer
, size
);
1193 posix_write(self
, args
)
1199 if (!getargs(args
, "(is#)", &fd
, &buffer
, &size
))
1202 size
= write(fd
, buffer
, size
);
1205 return posix_error();
1206 return newintobject((long)size
);
1210 posix_fstat(self
, args
)
1217 if (!getargs(args
, "i", &fd
))
1220 res
= fstat(fd
, &st
);
1223 return posix_error();
1224 return mkvalue("(llllllllll)",
1238 posix_fdopen(self
, args
)
1242 extern int fclose
PROTO((FILE *));
1246 if (!getargs(args
, "(is)", &fd
, &mode
))
1249 fp
= fdopen(fd
, mode
);
1252 return posix_error();
1253 /* From now on, ignore SIGPIPE and let the error checking
1256 (void) signal(SIGPIPE
, SIG_IGN
);
1258 return newopenfileobject(fp
, "(fdopen)", mode
, fclose
);
1262 posix_pipe(self
, args
)
1268 if (!getargs(args
, ""))
1274 return posix_error();
1275 return mkvalue("(ii)", fds
[0], fds
[1]);
1278 static struct methodlist posix_methods
[] = {
1279 {"chdir", posix_chdir
},
1280 {"chmod", posix_chmod
},
1281 {"chown", posix_chown
},
1282 {"getcwd", posix_getcwd
},
1284 {"link", posix_link
},
1286 {"listdir", posix_listdir
},
1287 {"lstat", posix_lstat
},
1288 {"mkdir", posix_mkdir
},
1290 {"nice", posix_nice
},
1292 #ifdef HAVE_READLINK
1293 {"readlink", posix_readlink
},
1295 {"rename", posix_rename
},
1296 {"rmdir", posix_rmdir
},
1297 {"stat", posix_stat
},
1299 {"symlink", posix_symlink
},
1301 {"system", posix_system
},
1302 {"umask", posix_umask
},
1304 {"uname", posix_uname
},
1306 {"unlink", posix_unlink
},
1308 {"utime", posix_utime
},
1311 {"times", posix_times
},
1313 {"_exit", posix__exit
},
1314 {"execv", posix_execv
},
1315 {"execve", posix_execve
},
1317 {"fork", posix_fork
},
1318 {"getegid", posix_getegid
},
1319 {"geteuid", posix_geteuid
},
1320 {"getgid", posix_getgid
},
1322 {"getpid", posix_getpid
},
1324 {"getpgrp", posix_getpgrp
},
1327 {"getppid", posix_getppid
},
1328 {"getuid", posix_getuid
},
1329 {"kill", posix_kill
},
1331 {"popen", posix_popen
},
1333 {"setuid", posix_setuid
},
1334 {"setgid", posix_setgid
},
1336 {"setpgrp", posix_setpgrp
},
1338 {"wait", posix_wait
},
1341 {"waitpid", posix_waitpid
},
1344 {"setsid", posix_setsid
},
1347 {"setpgid", posix_setpgid
},
1349 #ifdef HAVE_TCGETPGRP
1350 {"tcgetpgrp", posix_tcgetpgrp
},
1352 #ifdef HAVE_TCSETPGRP
1353 {"tcsetpgrp", posix_tcsetpgrp
},
1355 {"open", posix_open
},
1356 {"close", posix_close
},
1358 {"dup2", posix_dup2
},
1359 {"lseek", posix_lseek
},
1360 {"read", posix_read
},
1361 {"write", posix_write
},
1362 {"fstat", posix_fstat
},
1363 {"fdopen", posix_fdopen
},
1365 {"pipe", posix_pipe
},
1368 {NULL
, NULL
} /* Sentinel */
1378 m
= initmodule("nt", posix_methods
);
1379 d
= getmoduledict(m
);
1381 /* Initialize nt.environ dictionary */
1382 v
= convertenviron();
1383 if (v
== NULL
|| dictinsert(d
, "environ", v
) != 0)
1384 fatal("can't define nt.environ");
1387 /* Initialize nt.error exception */
1388 PosixError
= newstringobject("nt.error");
1389 if (PosixError
== NULL
|| dictinsert(d
, "error", PosixError
) != 0)
1390 fatal("can't define nt.error");
1398 m
= initmodule("posix", posix_methods
);
1399 d
= getmoduledict(m
);
1401 /* Initialize posix.environ dictionary */
1402 v
= convertenviron();
1403 if (v
== NULL
|| dictinsert(d
, "environ", v
) != 0)
1404 fatal("can't define posix.environ");
1407 /* Initialize posix.error exception */
1408 PosixError
= newstringobject("posix.error");
1409 if (PosixError
== NULL
|| dictinsert(d
, "error", PosixError
) != 0)
1410 fatal("can't define posix.error");